网络编程 套接字socket 及 粘包 (3)

总结 : 将 len 与 struct 结合使用

方案一 low版解决方案 # server 模拟远程控制主机cmd命令 import socket import struct import subprocess server = socket.socket() server.bind((\'127.0.0.1\', 8080)) server.listen(5) while 1: while 1: conn, addr = server.accept() try: cmd = conn.recv(1024) obj = subprocess.Popen(cmd.decode(\'utf-8\'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) ret = obj.stdout.read() + obj.stderr.read() print(f\'准备发送{len(ret)}个字节\') ret_len = struct.pack(\'i\',len(ret)) # 包装固定4个字节 报头 conn.send(ret_len) # 发送报头 conn.send(ret) # 发送真实数据 except Exception: break conn.close() server.close() # 但是low版本有问题: # 1,报头不只有总数据大小,而是还应该有MD5数据,文件名等等一些数据。 # 2,通过struct模块直接数据处理,不能处理太大。 # client import socket import struct client = socket.socket() client.connect((\'127.0.0.1\', 8080)) while 1: cmd = input(">>>").strip() client.send(cmd.encode(\'utf-8\')) # 发送命令 from_server_head = client.recv(4) # 接收server包装过的固定报头 from_server_head_int = struct.unpack(\'i\',from_server_head)[0] # 反序列报头是 元组 , +[0]才是报头 # 解析报头 print(f\'准备接收{from_server_head_int}个字节\') from_server_data = b\'\' while from_server_head_int > len(from_server_data): from_server_data += client.recv(1024) # 接收真实数据 print(from_server_data.decode(\'gbk\')) print(f\'客户端接收了{len(from_server_data)}个字节\') client.close() low版的局限性 问题一

非常大的数据 直接用struct 会报错

问题二

报头信息不可能只包含数据总大小 / md5 , 文件名 , 路径ct

方法二 旗舰版 / 可自定制报头版 传输流程

整个流程的大致解释:
我们可以把 ,字典里包含将要发送的真实数据的描述信息(大小啊之类的),然后 json序列化,然后用 struck 将序列化后的数据长度打包成
我们在网络上传输的所有数据 都叫做 数据包 ,数据包里的所有数据都叫做 报文,报文里面不止有你的数据,还有ip地址、mac地址、端口号等等,其实所有的报文都有报头,这个报头是协议规定的,看一下
发送时:

先发报头长度

再编码报头内容然后发送

最后发真实内容

接收时:

先手报头长度,用struct取出来

根据取出的长度收取报头内容,然后 解码,反序列化

从反序列化的结果中取出待取数据的描述信息,然后去取真实的数据内容

服务(器)端 # server import socket import subprocess import struct import json server = socket.socket() server.bind((\'127.0.0.1\', 8088)) server.listen(5) while 1: conn,addr = server.accept() print(\'start\') try: cmd = conn.recv(1024) print(f\'{cmd.decode("utf-8")}\') obj = subprocess.Popen(cmd.decode(\'utf-8\'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) ret = obj.stdout.read() + obj.stderr.read() ret = ret.decode(\'gbk\').encode(\'utf-8\') # 1.制作 字典式 报头 head_dict = {\'md5\':\'jrwiwfwr432knd324n23n2j131k\', \'file_name\':\'朝花夕拾\', \'file_size\':len(ret)} # 2.将报头字典转化成json字符串 head_dict_json = json.dumps(head_dict) # 3. 将json字符串 转化成bytes head_dict_json_bytes = head_dict_json.encode(\'utf-8\') # 4. 获取报头的长度 head_len = len(head_dict_json_bytes) # 5.将长度转化成固定的4个字节 head_len_bytes = struct.pack(\'i\',head_len) # 6. 发送固定的4个字节报头 conn.send(head_len_bytes) # 7. 发送字典 conn.send(head_dict_json_bytes) # 8. 发送原数据 conn.send(ret) except ConnectionResetError: break conn.close() server.close() 客户端 import socket import struct import json client = socket.socket() client.connect((\'127.0.0.1\', 8088)) # 发消息 while 1: cmd = input(\'>>>\') client.send(cmd.encode(\'utf-8\')) # 1. 接收报头 head_4 = client.recv(4) # 2. 将报头反解回int类型 head_size = struct.unpack(\'i\',head_4)[0] # 接收 并 解析4个字节的报头 ret = json.loads(client.recv(head_size).decode(\'utf-8\')) # 接收 并 转化 固定长度的字典 print(ret) # 字典 recv_date = b\'\' while len(recv_date) < head_size: recv_date += client.recv(1024) print(recv_date.decode("utf-8")) client.close()

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwzfys.html