python网络编程:TCP通讯模板、粘包及解决方案、自定义报头
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
python⽹络编程:TCP通讯模板、粘包及解决⽅案、⾃定义报头本⽂⽬录:
⼀、TCP通讯模板
TCP客户端
import socket
c = socket.socket()
# 连接服务器
c.connect(("127.0.0.1",65535))
while True:
# 发送数据
msg = input(">>>:")
if not msg:continue
c.send(msg.encode("utf-8"))
print("send!")
# 收数据
data = c.recv(1024).decode("utf-8")
print("receiver!")
print(data)
# 关闭资源
c.close()
TCP服务器
import socket
# 使⽤TCP 可以直接默认
server = socket.socket()
# 指定端⼝和 ip 端⼝ 0 - 1023是系统保留的
server.bind(("127.0.0.1",65535))
# 监听请求参数为最⼤半连接数(三次握⼿未完成的请求可能是服务器来不及客户端恶意攻击)
server.listen(5)
# 为了可以不断的接受客户端连接请求
while True:
# 接受连接请求
c,addr = server.accept()
# 为了可以重复收发数据
while True:
try:
# 1024 程序的最⼤缓冲区容量返回值类型为bytes类型
data = c.recv(1024).decode("utf-8")
# 如果客户端断开连接(客户端调⽤了close) recv 返回值为空此时应该结束循环
if not data:# 在linux中客户端异常关闭服务器也会收空
print("client closed!")
c.close()
break
#解码
print(data)
# 回复数据将原始数据转为⼤写
c.send(data.upper().encode("utf-8"))
except ConnectionResetError:
print("客户端异常关闭!!")
c.close()
break
# 关闭资源
server.close()
# TCP断开连接的正确姿势
# 客户端调⽤close
# 服务器判断如果接收数据为空则相应的调⽤close
⼆、远程CMD程序
CMD客户端
import socket
c = socket.socket()
# 连接服务器
c.connect(("127.0.0.1",65535))
while True:
# 发送数据
msg = input(">>>:")
if not msg:continue
c.send(msg.encode("utf-8"))
# while True:
# # 收数据
data = c.recv(1024).decode("gbk")
print(data)
# 关闭资源
c.close()
# 问题? 服务器发送的数据超过了接收端缓冲区⼤⼩可直接修改⼤⼩来满⾜服务器传输的⼤⼩但是不长远# 上述问题称之为粘包
# 思考: 循环每次读取⼀⼩部分直到取完为⽌
# 什么时候可以结束循环前提是让客户端直知道你的数据到底有多长
# 正确思路:
"""
发送⽅
1.先告诉对⽅你要发的数据的长度
2.在发送真实数据
接收⽅
1.先接收数据的长度信息
2.根据长度信息循环获取直到以获取的长度等于总长度
"""
CMD客户端2
import socket,time
c = socket.socket()
# 连接服务器
c.connect(("127.0.0.1",65535))
while True:
# 发送数据
c.send("dir".encode("utf-8"))
time.sleep(1)
c.send("dir".encode("utf-8"))
data = c.recv(1024).decode("gbk")
print(data)
# 关闭资源
c.close()
# 问题2 当客户端连续两⾏代码都发送⼀个dir时服务器收到了⼀个dirdir
# 两个命令黏在⼀起
# TCP协议内的⼀个nagle算法如果数据量⼩并且时间间隔短会将数据合并⼀个包
CMD服务器
# 1.服务器先启动 -> 客户端发送指令 -> 服务器接收后使⽤subprocess执⾏命令->将执⾏结果返回给客户端import socket,subprocess
# 使⽤TCP 可以直接默认
server = socket.socket()
# 指定端⼝和 ip 端⼝ 0 - 1023是系统保留的
server.bind(("127.0.0.1",65535))
# 监听请求参数为最⼤半连接数(三次握⼿未完成的请求可能是服务器来不及客户端恶意攻击) server.listen(5)
# 为了可以不断的接受客户端连接请求
while True:
# 接受连接请求
c,addr = server.accept()
# 为了可以重复收发数据
while True:
try:
# 1024 程序的最⼤缓冲区容量返回值类型为bytes类型
cmd = c.recv(1024).decode("utf-8")
# 如果客户端断开连接(客户端调⽤了close) recv 返回值为kong 此时应该结束循环
if not cmd:# 在linux中客户端异常关闭服务器也会收空
print("client closed!")
c.close()
break
#解码
print(cmd)
# 执⾏命令
p = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) # 将错误信息和正确信息拼接到⼀起
res = p.stdout.read() + p.stderr.read()
print("执⾏结果长",len(res))
# 将执⾏结果发送给客户端
c.send(res)
except ConnectionResetError:
print("客户端异常关闭!!")
c.close()
break
# 关闭资源
server.close()
# TCP断开连接的正确姿势
# 客户端调⽤close
# 服务器判断如果接收数据为空则相应的调⽤close
三、解决粘包问题
CMD客户端
import socket,struct
c = socket.socket()
# 连接服务器
c.connect(("127.0.0.1",65535))
while True:
# 发送数据
msg = input(">>>:")
if not msg:continue
c.send(msg.encode("utf-8"))
# 1.先获取长度
bytes_len = c.recv(4) #对⽅是i格式固定4字节
# 2.转回整型
total_len = struct.unpack("i",bytes_len)[0]
# 已经接收的长度
recv_len = 0
# ⼀个表⽰最终数据的bytes
finally_data = b''
# 3.收到的长度⼩于总长度就继续
while recv_len < total_len:
# 循环收数据
data = c.recv(1024)
recv_len += len(data)
finally_data += data
# 整体解码
print(finally_data.decode("gbk"))
# 关闭资源
c.close()
# 问题? 服务器发送的数据超过了接收端缓冲区⼤⼩可直接修改⼤⼩来满⾜服务器传输的⼤⼩但是不长远# 上述问题称之为粘包
# 思考: 循环每次读取⼀⼩部分直到取完为⽌
# 什么时候可以结束循环前提是让客户端直知道你的数据到底有多长
# 正确思路:
"""
发送⽅
1.先告诉对⽅你要发的数据的长度
2.在发送真实数据
接收⽅
1.先接收数据的长度信息
2.根据长度信息循环获取直到以获取的长度等于总长度
⾃定义报头未讲
"""
CMD服务器
# 1.服务器先启动 -> 客户端发送指令 -> 服务器接收后使⽤subprocess执⾏命令->将执⾏结果返回给客户端import socket,subprocess,struct
# 使⽤TCP 可以直接默认
server = socket.socket()
# 指定端⼝和 ip 端⼝ 0 - 1023是系统保留的
server.bind(("127.0.0.1",65535))
# 监听请求参数为最⼤半连接数(三次握⼿未完成的请求可能是服务器来不及客户端恶意攻击) server.listen(5)
# 为了可以不断的接受客户端连接请求
while True:
# 接受连接请求
c,addr = server.accept()
# 为了可以重复收发数据
while True:
try:
# 1024 程序的最⼤缓冲区容量返回值类型为bytes类型
cmd = c.recv(1024).decode("utf-8")
# 如果客户端断开连接(客户端调⽤了close) recv 返回值为kong 此时应该结束循环
if not cmd:# 在linux中客户端异常关闭服务器也会收空
print("client closed!")
c.close()
break
#解码
print(cmd)
# 执⾏命令
p = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) # 将错误信息和正确信息拼接到⼀起
res = p.stdout.read() + p.stderr.read()
print("执⾏结果长",len(res))
# 1.先发送数据的长度
data_len = len(res)
# 长度是⼀个整型需要转为字节 1000 b'\x001' 2000 b'\x001\x002'
# 另外需要保证长度信息转换后的结果长度是固定的否则客户端也会粘包(不知道取多少字节)
# struct 模块负责将python中的数据类型转为c语⾔中结构体
# 整型转字节
bytes_len = struct.pack("i",data_len)
c.send(bytes_len)
# 2.发送真实数据
c.send(res)
except ConnectionResetError:
print("客户端异常关闭!!")
c.close()
break
# 关闭资源
server.close()
# TCP断开连接的正确姿势
# 客户端调⽤close
# 服务器判断如果接收数据为空则相应的调⽤close
#structTest.py⽂件
import struct
# 整型转字节 i 表⽰int 长度为4字节 q表⽰long int 长度为8字节print(len(struct.pack("q",10240000000)))
# 字节转整型得到⼀个元祖
print(struct.unpack("q",struct.pack("q",10240000000))[0])
四、解决粘包问题2
CMD客户端
import socket,struct,json
c = socket.socket()
# 连接服务器
c.connect(("127.0.0.1",65535))
while True:
# 发送数据
msg = input(">>>:")
if not msg:continue
c.send(msg.encode("utf-8"))
# 1.先获取报头长度
bytes_len = c.recv(4) #对⽅是i格式固定4字节
# 2.转回整型
head_len = struct.unpack("i",bytes_len)[0]
# 3.接受报头数据
head_bytes = c.recv(head_len)
# 4.转为json字符串并转为字典
head_dic = json.loads(head_bytes.decode("utf-8"))
print(head_dic)
# 已经接收的长度
recv_len = 0
# ⼀个表⽰最终数据的bytes
finally_data = b''
# 3.收到的长度⼩于总长度就继续
while recv_len < head_dic["total_size"]:
# 循环收数据
data = c.recv(1024)
recv_len += len(data)
finally_data += data
# 整体解码
print(finally_data.decode("gbk"))
# 关闭资源
c.close()
# 问题? 服务器发送的数据超过了接收端缓冲区⼤⼩可直接修改⼤⼩来满⾜服务器传输的⼤⼩但是不长远# 上述问题称之为粘包
# 思考: 循环每次读取⼀⼩部分直到取完为⽌
# 什么时候可以结束循环前提是让客户端直知道你的数据到底有多长
# 正确思路:
"""
发送⽅
1.先告诉对⽅你要发的数据的长度
2.在发送真实数据
接收⽅
1.先接收数据的长度信息
2.根据长度信息循环获取直到以获取的长度等于总长度
⾃定义报头未讲
"""
CMD服务器
# 1.服务器先启动 -> 客户端发送指令 -> 服务器接收后使⽤subprocess执⾏命令->将执⾏结果返回给客户端import socket,subprocess,struct,json
# 使⽤TCP 可以直接默认
server = socket.socket()
# 指定端⼝和 ip 端⼝ 0 - 1023是系统保留的
server.bind(("127.0.0.1",65535))
# 监听请求参数为最⼤半连接数(三次握⼿未完成的请求可能是服务器来不及客户端恶意攻击) server.listen(5)
# 为了可以不断的接受客户端连接请求
while True:
# 接受连接请求
c,addr = server.accept()
# 为了可以重复收发数据
while True:
try:
# 1024 程序的最⼤缓冲区容量返回值类型为bytes类型
cmd = c.recv(1024).decode("utf-8")
# 如果客户端断开连接(客户端调⽤了close) recv 返回值为kong 此时应该结束循环
if not cmd:# 在linux中客户端异常关闭服务器也会收空
print("client closed!")
c.close()
break
#解码
print(cmd)
# 执⾏命令
p = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) # 将错误信息和正确信息拼接到⼀起
res = p.stdout.read() + p.stderr.read()
print("执⾏结果长",len(res))
# 1.组装⼀个报头信息
head_dic = {
"name":"仓⽼师视频教学如何做炸鸡!",
"md5":"asasasasaas",
"total_size":len(res),
"type":"video"
}
# 2.转json字符串
head_str = json.dumps(head_dic)
# 3.转字节
head_bytes = head_str.encode("utf-8")
# 4.发送报头长度
bytes_len = struct.pack("i",len(head_bytes))
c.send(bytes_len)
# 5.发送报头
c.send(head_bytes)
# 6.发送真实数据
c.send(res)
except ConnectionResetError:
print("客户端异常关闭!!")
c.close()
break
# 关闭资源
server.close()
# TCP断开连接的正确姿势
# 客户端调⽤close
# 服务器判断如果接收数据为空则相应的调⽤close
# structTest.py⽂件
import struct
# 整型转字节 i 表⽰int 长度为4字节 q表⽰long int 长度为8字节print(len(struct.pack("q",10240000000)))
# 字节转整型得到⼀个元祖
print(struct.unpack("q",struct.pack("q",10240000000))[0])。