socket沾包问题

为什么会沾包

  1. 发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,会合到一起,产生粘包)
  2. 接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包) 

注意:只有TCP有粘包现象,UDP永远不会粘包

自制报头解决沾包

服务端
  1. 把真实数据转换成bytes -->header_bytes
  2. 使用struct.pack('i',len(header_bytes)),生成一个固定长度的报头(4字节的bytes)
  3. 使用sendall(报头+ 真实数据的bytes) 返回数据给客户端
 
客户端
    1. 客户端先recv(4),接收报头信息
    2. 然后使用struct.unpach('i',报头)解包,获取真实数据的长度
    3. 使用recv(数据长度)接收数据
import json
import struct
from socket import *
s=socket(AF_INET,SOCK_STREAM)
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind(('127.0.0.1',8081))
s.listen(5)
while True:
    print('等待链接...')
    conn,addr=s.accept()
    while True:
        try:
            data=conn.recv(1024)
            dic = {'file':'hanqian','size':12345,'md5':'abcdefg'}
            dic_bytes = json.dumps(dic).encode('utf-8')  # 字符串编码后是bytes类型
            h_len = struct.pack('i',len(dic_bytes))  # h_len=4  报头固定长度
            print('报头:',h_len)
            conn.send(h_len+dic_bytes)  # 给客户端返回数据,对端会先接收4个字节获取报头,然后使用struct.unpack('i',报头)解包获取真实数据长度,然后调用s。recv
        except ConnectionResetError as e:
            break
    conn.close()  # 关闭链接
s.close()  # 关闭监听端口
服务端-解决沾包
import struct
from socket import *
s=socket(AF_INET,SOCK_STREAM)
s.connect(('127.0.0.1',8081))
while True:
    msg=input('输入要发送的数据>>: ').strip()
    if not msg: continue  住
    s.send(msg.encode('utf-8'))  # 发送数据(只能发送字节类型)
    h_val = s.recv(4)  # 先使用4个字节接收报头,获取的是打包后的值(bytes类型)
    print('报头:',h_val)
    data_size = struct.unpack('i',h_val)[0]  # 解使用打包的值解包,data_size=真实数据大小(int类型)
    print('真实数据长度:',data_size)
    data=s.recv(data_size)  # 接受数据
    print(data.decode('gbk'))
客户端-解决沾包
原文地址:https://www.cnblogs.com/hanqian/p/6508106.html