- 粘包:发送方发送两个字符串”hello”, ”world”,接收方却一次性接收到了”helloworld”
- 分包:发送方发送字符串”helloworld”,接收方却接收到了两个字符串”hello”和”world”
1 服务端
import socketimport structHOST = ''PORT = 1234# FIFO消息队列dataBuffer = bytes()# 自定义消息头的长度headerSize = 12# 定义数据包的个数sn = 0# 正文数据处理def dataHandle(headPack, body): global sn sn += 1 print(f"第{sn}个数据包") print(body.decode()) print("\n")if __name__ == '__main__': with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind((HOST, PORT)) s.listen(1) conn, addr = s.accept() with conn: print('Connected by', addr) while True: data = conn.recv(1024) if data: # 把数据存入缓冲区,类似于push数据 dataBuffer += data while True: if len(dataBuffer) < headerSize: print("数据包(%s Byte)小于消息头部长度,跳出小循环" % len(dataBuffer)) break # 读取包头 # struct中!代表Network order,3I代表3个unsigned int数据 headPack = struct.unpack('!3I', dataBuffer[:headerSize]) bodySize = headPack[1] # 分包情况处理,跳出函数继续接收数据 if len(dataBuffer) < headerSize+bodySize : print("数据包(%s Byte)不完整(总共%s Byte),跳出小循环" % (len(dataBuffer), headerSize+bodySize)) break # 读取消息正文的内容 body = dataBuffer[headerSize:headerSize+bodySize] # 数据处理 dataHandle(headPack, body) # 数据出列 dataBuffer = dataBuffer[headerSize+bodySize:] # 获取下一个数据包,类似于把数据pop出
2 客户端
import socketimport timeimport structimport jsonhost = "localhost"port = 1234ADDR = (host, port)if __name__ == '__main__': client = socket.socket() client.connect(ADDR) # 正常数据包定义 ver = 1 body = json.dumps(dict(hello="world")) print(body) cmd = 101 header = [ver, body.__len__(), cmd] headPack = struct.pack("!3I", *header) sendData1 = headPack+body.encode() # 分包数据定义 ver = 2 body = json.dumps(dict(hello="world2")) print(body) cmd = 102 header = [ver, body.__len__(), cmd] headPack = struct.pack("!3I", *header) sendData2_1 = headPack+body[:2].encode() sendData2_2 = body[2:].encode() # 粘包数据定义 ver = 3 body1 = json.dumps(dict(hello="world3")) print(body1) cmd = 103 header = [ver, body1.__len__(), cmd] headPack1 = struct.pack("!3I", *header) ver = 4 body2 = json.dumps(dict(hello="world4")) print(body2) cmd = 104 header = [ver, body2.__len__(), cmd] headPack2 = struct.pack("!3I", *header) sendData3 = headPack1+body1.encode()+headPack2+body2.encode() # 正常数据包 client.send(sendData1) time.sleep(3) # 分包测试 client.send(sendData2_1) time.sleep(0.2) client.send(sendData2_2) time.sleep(3) # 粘包测试 client.send(sendData3) time.sleep(3) client.close()