缓冲区: 将程序和网络解耦
输入缓冲区
输出缓冲区
print('>>>>', server.getsockopt(SOL_SOCKET, SO_SNDBUF)) 查看输出缓冲区大小 print('>>>>', server.getsockopt(SOL_SOCKET, SO_RCVBUF)) 查看输入缓冲区大小
import subprocess sub_obj = subprocess.Popen( "dir", # 系统指令 shell=True, # 固定 stdout=subprocess.PIPE, # 标准输出 PIPE 管道,保存着指令的执行结果 stderr=subprocess.PIPE # 标准错误输出 )
两种黏包现象:
1 连续的小包可能会被优化算法给组合到一起进行发送
2 第一次如果发送的数据大小2000B接收端一次性接受大小为1024,这就导致剩下的内容会被下一次recv接收到,导致结果错乱
解决方案
方案一:由于双方不知道对方发送数据的长度,导致接收的时候,可能接收不全,或者多接收另外一次发送的信息内容,
所以在发送真实数据之前,要先发送数据的长度,接收端根据长度来接收后面的真实数据,但是双方有一个交互确认的过程
方案二:
Struct模块,
打包:struct.pack(‘i’,长度)
解包:struct.unpack(‘i’,字节)
服务端 import socket import subprocess import struct server = socket.socket() ip_port = ('127.0.0.1', 8001) server.bind(ip_port) server.listen() conn, addr = server.accept() while 1: from_client_cmd = conn.recv(1024) print(from_client_cmd.decode('utf-8')) # 接收到客户端 发送来的系统指令,我服务端通过subprocess模块到服务端自己的系统里面执行这条指令 sub_obj = subprocess.Popen( from_client_cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, # 正确结果位置 stderr=subprocess.PIPE # 错误 ) # 从管道里边拿出结果,通过sunprocess.Popen 的实例化对象.stdout.read()方法来获取管道中的结果 std_msg = sub_obj.stdout.read() # 为了解决黏包现象,我们统计了一下消息的长度,先将消息的长度发送给客户端,客户端通过这个长度来接收后面我们要发送的真实数据 std_msg_len = len(std_msg) print('指令的执行结果长度>>>>', len(std_msg)) msg_lenint_struct = struct.pack('i',std_msg_len) conn.send(msg_lenint_struct+std_msg)
客户端 import socket import struct client = socket.socket() client.connect(('127.0.0.1', 8001)) while 1: cmd = input('请输入指令:') # 发送指令 client.send(cmd.encode('utf-8')) # 接收数据长度,首先接收4个字节长度的数据,因为这个4个字节是长度 server_res_len = client.recv(4) msg_len = struct.unpack('i', server_res_len)[0] print('来自服务端的消息长度', msg_len) # 通过解包出来的长度,来接收后面的真实数据 server_cmd_result = client.recv(msg_len) print(server_cmd_result.decode('gbk'))