socket(TCP-粘包)通讯之Python实现

所谓粘包问题主要还是C/S两端数据传输时  因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的
根本原因:
粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一个TCP段。若连续几次需要send的数据都很少,通常TCP会根据优化算法把这些数据合成一个TCP段后一次发送出去,这样接收方就收到了粘包数据。

解决方法:

1、自定义字典类型 的数据报头{xx:a,data_len:1090} 计算出该报头的长度(len(字节)),
2、使用struct.pack('i',报头长度(一个数字))把一个数字压缩成固定的size 4个字节,发送给对端。
3、对端 struct.unpack(‘i’,recv(4))接收固定大小4个字节;这就是接收到了 报头的长度。
4、recv(报头长度)这就是发送过来的报头信息了

   


1、Server实现
address = ('localhost', 9102)

# AF_INET = ipv4;  SOCK_STREAM:TCP
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 
s.bind(address)
# 监听
s.listen(5)while True:
    print('----server wait')
    conn, addr = s.accept()

    data_head = TCP_base.parse_head(conn)
    data_len = data_head['data_len']
    data = conn.recv(data_len)
    print('--data----------', data)

    time.sleep(5)

    head_len, head_bytes = TCP_base.build_header('this is tet', data)
    conn.send(head_len)
    conn.send(head_bytes)
    conn.sendall('pk finish, new is bad'.encode('utf-8'))
    
    conn.close()

TCP_Base:

负责每次数据的头部的信息的解析与拼接

def parse_head(conn):
    head_len = conn.recv(4)  # s1 head-len
    head_len = struct.unpack('i', head_len)[0]
    # print('--head-len-', head_len)
    data_head = conn.recv(head_len).decode('utf-8')
    # print('--headinfo------', data_head)
    data_head = json.loads(data_head)
    # print('--headinfo-json-', data_head)
    return data_head

def build_header(id, data):
    data_len = len(data)
    head_info = {'id': id, 'data_len': data_len}
    head_json = json.dumps(head_info)
    head_bytes = head_json.encode('utf-8')
    head_bytes_len = len(head_bytes)

    head_len = struct.pack('i', head_bytes_len)

    return head_len, head_bytes

 2、Client实现

self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 1 connect
        self.s.connect(self.ip_port)
        # 2 require send data
        # self.s.sendall(cmd.encode(self.utf_8))
        head_len, head_info = TCP_base.build_header(cmd, data)
        self.s.send(head_len)   # send head_len 4 Bit
        self.s.send(head_info)  # send head
        self.s.sendall(data.encode(self.utf_8)) #send datas

        # 3 recv data
        # data = self.s.recv(1024).decode(self.utf_8)
        data_head = TCP_base.parse_head(self.s)
        data_len = data_head['data_len']
        data = self.s.recv(data_len)
        print('--data----------', data)
        # print(data)
        # 4 close
        self.s.close()


猜你喜欢

转载自www.cnblogs.com/xiaoniu-666/p/10772573.html