使用struct模块解决黏包问题

 1 '''
 2 远程执行cmd命令程序
 3 如果不使用struct模块,ipconfig等会返回长数据的命令会发生黏包现象
 4 '''
 5 import socket
 6 import struct
 7 
 8 sk = socket.socket()
 9 sk.bind(("127.0.0.1", 8080))
10 sk.listen()
11 conn, addr = sk.accept()
12 while True:
13     cmd = input(">>>")
14     if cmd == "q":
15         conn.send(b"q")
16         break
17     conn.send(bytes(cmd,encoding="gbk"))
18     # windows系统的命令行的编码格式是GBK所以要进行GBK转码
19     num = conn.recv(4)
20     # 接收返回数据的长度
21     num = int(struct.unpack("i",num)[0])
22     # 将接收的bytes类型的struct转换的数字解码,因为返回的是元组所以取元组的第一个,并且下面要用的类型是整数型,转换成int类型
23     print(conn.recv(num).decode("gbk"))
24     # 接收上面传进来大小的数据,解码gbk,打印
25     # 发送多少接收多少就不会产生黏包现象了
26 
27 conn.close()
28 sk.close()
server
 1 import socket
 2 import struct
 3 import subprocess
 4 
 5 sk = socket.socket()
 6 sk.connect(("127.0.0.1", 8080))
 7 while True:
 8     cmd = sk.recv(1024).decode("gbk")
 9     # Windows命令行是gbk编码,使用gbk解码
10     if cmd == "q":
11         break
12     res = subprocess.Popen(cmd,shell=True,
13                      stdout=subprocess.PIPE,
14                      stderr=subprocess.PIPE)
15     # 使用subprocess模块执行cmd命令
16     # 第一个参数是要执行的命令
17     # shell=True 表示执行的是系统shell命令
18     # stdout 执行成功输出信息,保存到管道
19     # stderr 执行失败输出信息,保存到管道
20     stdout = res.stdout.read()
21     # 读取执行成功信息
22     stderr = res.stderr.read()
23     # 读取执行失败信息
24     str_len = len(stdout)+len(stderr)
25     # 取执行成功和失败信息的长度和
26     num = struct.pack("i",str_len)
27     # 使用struct进行数字固定长度编码
28     # “i” 表示进行转换的是int类型 -> 转换完成后会是固定4字节的bytes类型
29     # 第二个参数是长度数字
30     sk.send(num)
31     # 将长度发送
32     sk.send(stdout)
33     # 发送执行成功信息
34     sk.send(stderr)
35     # 发送执行失败信息
36 
37 sk.close()
client

 

posted @ 2019-08-19 18:13  长江尾  阅读(134)  评论(0编辑  收藏  举报