kkpiece 2020-03-03
粘包问题出现在TCP连接下。
由于client 端通过 tcp 连接 向 server端发送消息,多条消息之间没有明显的区分,导致server端在接收时,会将前一条消息的 结尾与下一天消息的开头放入一个缓冲区进行接收。
导致两条数据粘在一起, 称为粘包。
解决粘包的思路为,在发送一条消息时 将前4个字符设置为消息的长度,让接收端知道消息的长度即可区分不同的消息。
粘包问题及解决 / pro.py
import struct def sender(conn, msg: bytes): # 计算消息的长度 pack_head = struct.pack('i', len(msg)) # 发送消息的长度 conn.send(pack_head) # 发送消息 conn.send(msg) def receiver(conn) -> str: # 获取消息的长度 length = struct.unpack('i', conn.recv(4))[0] print(length) # 设置缓冲区大小为1024 buff_size = 1024 msg = '' while True: if length < buff_size: # 消息长度小于缓冲区大小 接收数据结束循环 recv_msg = conn.recv(length) msg += recv_msg.decode('utf-8') break else: # 消息长度大于缓冲区大小 # 接收缓冲区大小的数据 # 数据长度减去已经接收的长度 recv_msg = conn.recv(length) length -= buff_size msg = recv_msg.decode('utf-8') return msg
server.py
import socket, subprocess,traceback from 粘包问题及解决 import proto if __name__ == '__main__': s = socket.socket() s.bind(('127.0.0.1', 8000)) s.listen() while True: print('等待连接') conn, addr = s.accept() while True: try: commend = proto.receiver(conn) except Exception as e: print('连接异常') conn.close() print(traceback.print_exc()) break if commend == 'exit': conn.close() break obj = subprocess.Popen(commend, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out = obj.stdout.read() err = obj.stderr.read() if err: print("err:", err) proto.sender(conn, err) else: print("out", out) proto.sender(conn, out)
client.py
import socket from 粘包问题及解决 import proto if __name__ == '__main__': s = socket.socket() s.connect(('127.0.0.1', 8000)) while True: cmd = input("> ") proto.sender(s, cmd.encode('utf-8')) if cmd == 'exit': s.close() break print(proto.receiver(s))