一、服务端代码为:
1 import socket 2 import subprocess 3 import struct 4 5 phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 6 # phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 7 phone.bind(('127.0.0.1', 8081)) # 0-65535:0-1024给操作系统使用 8 phone.listen(5) 9 10 print('starting......') 11 while True: # 链接循环 12 conn, client_addr = phone.accept() 13 print(client_addr) 14 15 while True: # 通信循环 16 try: 17 # 1、收命令 18 cmd = conn.recv(1024) 19 if not cmd: # 适用于linux操作系统 20 break 21 print('客户端的数据', cmd) 22 23 # 2、执行命令,拿到结果 24 obj = subprocess.Popen(cmd.decode('utf-8'), shell=True, 25 stdout=subprocess.PIPE, 26 stderr=subprocess.PIPE) 27 28 stdout = obj.stdout.read() 29 stderr = obj.stderr.read() 30 # 3、把命令的结果返回给客户端 31 # 第一步:制作固定长度的报头 32 total_size = len(stdout) + len(stderr) 33 header = struct.pack('i', total_size) 34 35 # 第二步:把包头发送给客户端 36 conn.send(header) 37 38 # 第三步:再发送真实的数据 39 conn.send(stdout) 40 conn.send(stderr) 41 42 except ConnectionResetError: # 适用于Windows操作系统 43 break 44 45 conn.close() 46 47 phone.close()
二、客户端代码为:
1 import socket 2 import struct 3 4 5 phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 6 7 phone.connect(('127.0.0.1', 8081)) 8 9 while True: 10 # 1、发命令 11 cmd = input('>>:').strip() 12 if not cmd: 13 continue 14 phone.send(cmd.encode('utf-8')) 15 16 # 2、拿命令的结果,并打印 17 18 # 第一步:先收报头 19 header = phone.recv(4) 20 21 # 第二步:从报头中解析出对真实数据的描述信息(数据的长度) 22 total_size = struct.unpack('i', header)[0] 23 24 # 第三步: 接收真实的数据 25 recv_size = 0 26 recv_data = b'' 27 while recv_size < total_size: 28 res = phone.recv(1024) # 1024是一个坑 29 recv_data += res 30 recv_size += len(res) 31 print(recv_data.decode('gbk')) 32 33 phone.close()
在客户端依次输入,dir, ipconfig, dir,客户端结果为:
1 >>:dir 2 驱动器 C 中的卷是 OS 3 卷的序列号是 7849-BAF9 4 5 C:Usersxu516PycharmProjectsPython全栈开发第三模块网络编程 5 解决粘包问题简单版 的目录 6 7 2018/04/08 21:48 <DIR> . 8 2018/04/08 21:48 <DIR> .. 9 2018/04/08 21:40 128 struct模块的使用.py 10 2018/04/08 21:48 802 客户端.py 11 2018/04/08 21:48 1,487 服务端.py 12 3 个文件 2,417 字节 13 2 个目录 36,977,733,632 可用字节 14 15 >>:ipconfig 16 17 Windows IP 配置 18 19 20 无线局域网适配器 本地连接* 3: 21 22 媒体状态 . . . . . . . . . . . . : 媒体已断开连接 23 连接特定的 DNS 后缀 . . . . . . . : 24 25 以太网适配器 VMware Network Adapter VMnet1: 26 27 连接特定的 DNS 后缀 . . . . . . . : 28 本地链接 IPv6 地址. . . . . . . . : fe80::5d54:4c1:d7d6:c647%6 29 IPv4 地址 . . . . . . . . . . . . : 192.168.189.1 30 子网掩码 . . . . . . . . . . . . : 255.255.255.0 31 默认网关. . . . . . . . . . . . . : 32 33 以太网适配器 VMware Network Adapter VMnet8: 34 35 连接特定的 DNS 后缀 . . . . . . . : 36 本地链接 IPv6 地址. . . . . . . . : fe80::680e:7f79:aed1:fe62%10 37 IPv4 地址 . . . . . . . . . . . . : 192.168.254.1 38 子网掩码 . . . . . . . . . . . . : 255.255.255.0 39 默认网关. . . . . . . . . . . . . : 40 41 无线局域网适配器 WLAN: 42 43 连接特定的 DNS 后缀 . . . . . . . : DHCP HOST 44 本地链接 IPv6 地址. . . . . . . . : fe80::9c84:419c:e3af:89dd%11 45 IPv4 地址 . . . . . . . . . . . . : 192.168.0.106 46 子网掩码 . . . . . . . . . . . . : 255.255.255.0 47 默认网关. . . . . . . . . . . . . : 192.168.0.1 48 49 以太网适配器 蓝牙网络连接: 50 51 媒体状态 . . . . . . . . . . . . : 媒体已断开连接 52 连接特定的 DNS 后缀 . . . . . . . : 53 54 隧道适配器 Teredo Tunneling Pseudo-Interface: 55 56 连接特定的 DNS 后缀 . . . . . . . : 57 IPv6 地址 . . . . . . . . . . . . : 2001:0:9d38:953c:20d3:83ef:d86a:f024 58 本地链接 IPv6 地址. . . . . . . . : fe80::20d3:83ef:d86a:f024%2 59 默认网关. . . . . . . . . . . . . : :: 60 61 >>:dir 62 驱动器 C 中的卷是 OS 63 卷的序列号是 7849-BAF9 64 65 C:Usersxu516PycharmProjectsPython全栈开发第三模块网络编程 5 解决粘包问题简单版 的目录 66 67 2018/04/08 21:48 <DIR> . 68 2018/04/08 21:48 <DIR> .. 69 2018/04/08 21:40 128 struct模块的使用.py 70 2018/04/08 21:48 802 客户端.py 71 2018/04/08 21:48 1,487 服务端.py 72 3 个文件 2,417 字节 73 2 个目录 36,977,725,440 可用字节 74 75 >>:
从以上客户端输出结果可以看出,解决了粘包现象