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()