缓冲区,粘包,解决粘包的方法,

缓冲区:暂时存放传输数据的,防止你的程序在发送数据的时候卡主,提高代码运行效率

    输入缓冲区:recv

    输出缓冲区:send

    缓冲区有长度限制

MTU最大传输单元,网络层限制是1500B,每次发送数据的时候最好不要超过这个数

粘包

  粘包现象:

  1.连续发送小的数据,间隔时间很短,有可能一次就接受欧到了这几个连续的情节在一起的小数据,

  原因:未来提高tcp传输效率,内部提供了一个叫做Nagel算法,他的意思就是未来避免你连续发送小数据.

  2.当你一次接收的数据长度小于你一次发送的数据长度,那么一次接收完剩下的数据会在下一次接收数据的时候一起接收

  原因:面向流的传输

  粘包的根本原因:

    两端互相不知道对方发送数据的长度

  针对上面的原因有两种解决粘包的方法

  

    1在发送数据前,先发送数据的长度,name接收根据的长度来进行接收数据

 服务端:

    

import socket
import subprocess

server = socket.socket()
ip_port = ('192.168.15.113',8001)
server.bind(ip_port)
server.listen()
conn,addr = server.accept()
while 1:
#来自客户端的指令
print('等待接受信息。。。')
from_client_cmd = conn.recv(1024).decode('utf-8')
print(from_client_cmd)
sub_obj = subprocess.Popen(
from_client_cmd, #客户端的指令
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)

#接受到的返回信息是bytes类型的,并且windows系统的默认编码为gbk
server_cmd_msg = sub_obj.stdout.read()
# server_cmd_err = sub_obj.stderr.read().decode('gbk')
cmd_msg_len = str(len(server_cmd_msg))
print('指令返回的正确信息的长度>>>',cmd_msg_len)
# print('指令返回的正确信息>>>',server_cmd_msg)
# print('指令返回的错误信息...',server_cmd_err)

conn.send(cmd_msg_len.encode('gbk'))

from_client_ack = conn.recv(1024).decode('utf-8')
print('from_client_ack',from_client_ack)
if from_client_ack == 'ok':

conn.send(server_cmd_msg)
else:
continue

    

 客户端:

    

import socket
client = socket.socket()
server_ip_port = ('192.168.15.113',8001)
client.connect(server_ip_port)
while 1:
msg = input('请输入要执行的指令>>>')
client.send(msg.encode('utf-8'))
#先接收服务端要发送给我的信息的长度
from_server_msglen = int(client.recv(1024).decode('gbk'))
print('..........',from_server_msglen)
#给服务端回应一个收到了你的信息长度的确认信息
client.send('ok'.encode('utf-8'))

#拿到信息长度后,将信息长度作为参数给了recv,recv就按照这个长度大小来接受服务端后面要给我发送的数据
from_server_stdout = client.recv(from_server_msglen).decode('gbk')

print('收到的正确信息:', from_server_stdout)

# from_server_error = client.recv(1024).decode('utf-8')
# print('收到的错误信息:',from_server_error)

2. 把要发送的数据打成包的形式直接传输

服务端:

  

import socket
import subprocess
import struct

server = socket.socket()
ip_port = ('192.168.15.113',8001)
server.bind(ip_port)
server.listen()
conn,addr = server.accept()
while 1:
#来自客户端的指令
print('等待接受信息。。。')
from_client_cmd = conn.recv(1024).decode('utf-8')
print(from_client_cmd)
#通过subprocess模块执行服务端的系统指令,并且拿到指令执行结果
sub_obj = subprocess.Popen(
from_client_cmd, #客户端的指令
shell=True,
stdout=subprocess.PIPE, #标准输出:正确指令的执行结果在这里
stderr=subprocess.PIPE, #标准错误输出:错误指令的执行结果在这里
)
#接受到的返回信息是bytes类型的,并且windows系统的默认编码为gbk
server_cmd_msg = sub_obj.stdout.read()
# server_cmd_err = sub_obj.stderr.read().decode('gbk')
#首先计算出你将要发送的数据的长度
cmd_msg_len = len(server_cmd_msg)
#先对数据长度进行打包,打包成4个字节的数据,目的是为了和你将要发送的数据拼在一起,就好我们自定制了一个消息头
msg_len_stru = struct.pack('i',cmd_msg_len)
conn.send(msg_len_stru) #首先发送打包成功后的那4个字节的数据
conn.sendall(server_cmd_msg) #循环send数据,直到数据全部发送成功

  

客户端: 

    

import socket
import struct
client = socket.socket()
server_ip_port = ('192.168.15.113',8001)
client.connect(server_ip_port)
while 1:
msg = input('请输入要执行的指令>>>')
client.send(msg.encode('utf-8'))
#先接收服务端要发送给我的信息的长度,前4个字节,固定的
from_server_msglen = client.recv(4)
unpack_len_msg = struct.unpack('i',from_server_msglen)[0]
#接收数据长度统计,和服务端发给我的数据长度作比较,来确定跳出循环的条件
recv_msg_len = 0
#统计拼接接收到的数据,注意:这个不是统计长度
all_msg = b''
while recv_msg_len < unpack_len_msg:
every_recv_data = client.recv(1024)
#将每次接收的数据进行拼接和统计
all_msg += every_recv_data
#对每次接收到的数据的长度进行累加
recv_msg_len += len(every_recv_data)

print(all_msg.decode('gbk'))


  
原文地址:https://www.cnblogs.com/lilei1996/p/9811694.html