粘包问题
粘包问题:是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一个TCP段,若连续几次需要send的数据都很少,通常TCP会根据优化算法把这些数据合成一个TCP段后一次发出,这样接收方就收到了粘包数据。使用的算法是Nagle。
TCP协议是流式传输,没有开始没有结束,所以也就不知道在哪里分开粘结点。
自制报头解决粘包问题:
报头:固定长度、包含对将要发送的数据添加描述信息。
client端:
import socket import struct phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ip_port = ('127.0.0.1', 8081) phone.connect(ip_port) # 通信循环 while True: # 发消息 cmd = input('>>: ').strip() if not cmd: continue phone.send(bytes(cmd, encoding='utf-8')) # 收报头 收4个字节 baotou=phone.recv(4) # 定义的i的报头长度,用unpack去解报头,第0个是数据长度 data_size=struct.unpack('i',baotou)[0] # 收数据, recv_size=0 recv_data=b'' while recv_size < data_size: data=phone.recv(1024) recv_size+=len(data) recv_data+=data print(recv_data.decode('utf-8')) phone.close()
Server端:
#coding:utf-8 import socket import struct import subprocess phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) ip_port=('127.0.0.1',8081) phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) phone.bind(ip_port) phone.listen(5) #链接循环 while True: conn,addr=phone.accept() print('client addr',addr) #通讯循环 while True: try: cmd=conn.recv(1024) res=subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out_res=res.stdout.read() err_res=res.stderr.read() # 发送报头部分 data_size=len(out_res)+len(err_res) # 发送数据部分,定义报头长度为4个字节 conn.send(struct.pack('i',data_size)) #struck.pack是打包,i是代表4个字节 conn.send(out_res) conn.send(err_res) except Exception: break conn.close() phone.close()
------- END ------