python网络编程粘包处理
在python网络编程中两台电脑在进行收发数据时,其实不是直接将数据传输给对方。
对于发送者,执行
sendall/send
发送消息时,是将数据先发送至自己网卡的 写缓冲区 ,再由缓冲区将数据对于接受者,执行
recv
接收消息时,是从自己网卡的读缓冲区获取数据。
所以,如果发送者连续快速的发送了2条信息,接收者在读取时会认为这是1条信息,即:2个数据包粘在了一起。
粘包示例:这里ip是以本机默认ip,方便测试
客户端:发送方
-
import socket
-
#创建连接
-
client = socket.socket()
-
client.connect(('127.0.0.1', 8001))
-
-
#发送两条消息
-
client.sendall('学如初出之苗,不见其增'.encode('utf-8'))
-
client.sendall('日有所长'.encode('utf-8'))
-
#关闭连接
-
client.close()
服务端:接收方
-
import socket
-
#创建连接
-
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-
sock.bind(('127.0.0.1', 8001))
-
sock.listen(5)
-
-
#等待连接
-
conn, addr = sock.accept()
-
-
读取收到的数据并打印
-
client_data = conn.recv(1024)
-
print(client_data.decode('utf-8'))
-
#输出结果:学如初出之苗,不风其增日有所长
-
-
conn.close()
-
sock.close()
发送方分开发送了2条的消息,接收却是1条,显然是不合适的
解决粘包的问题
每次发送的消息时,都将消息划分为 头部(固定字节长度) 和 数据 两部分。例如:头部,用4个字节表示后面数据的长度。
发送数据,先发送数据的长度,再发送数据(或拼接起来再发送)。
接收数据,先读4个字节就可以知道自己这个数据包中的数据长度,再根据长度读取到数据。
对于头部需要一个数字并固定为4个字节,这个功能可以借助python的struct包来实现:
-
import struct
-
# i 表示4个字节的int
-
# 199 表示字节大小为199
-
v1 = struct.pack('i', 199)# 把199转成固定4字节
-
print(v1) # b'\xc7\x00\x00\x00'
-
-
v2 = struct.unpack('i', v1) # 4个字节转换为数字
-
print(v2) # 199
附上转字节大小图
接下来示例
发送方
-
import socket
-
import struct
-
-
client = socket.socket()
-
client.connect(('127.0.0.1', 8001))
-
-
# 第一条数据
-
data1 = '惰如磨刀之石'.encode('utf-8')
-
-
len1 = struct.pack('i', len(data1))# 获取要发送数据的字节长度
-
-
client.sendall(len1)# 先发送数据字节长度
-
client.sendall(data)# 发送数据
-
-
# 第二条数据
-
data2 = '不见其损,日有所耗'.encode('utf-8')
-
len2 = struct.pack('i', len(data2))
-
-
client.sendall(len2)
-
client.sendall(data2)
-
-
client.close()
接收方
-
import socket
-
import struct
-
#创建连接,等待连接
-
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-
sock.bind(('127.0.0.1', 8001))
-
sock.listen(5)
-
conn, addr = sock.accept()
-
-
# 固定读取4字节
-
header1 = conn.recv(4)
-
data_length1 = struct.unpack('i', header1)[0]
-
-
has_recv_len = 0
-
data1 = b""
-
while True:
-
length = data_length1 - has_recv_len
-
if length > 1024:
-
lth = 1024
-
else:
-
lth = length
-
chunk = conn.recv(lth)
-
# 可能一次收不完,自己可以计算长度再次使用recv收取,只到收完为止。 接收最大字节1024*8 = 8196
-
data1 = chunk
-
has_recv_len = len(chunk)
-
if has_recv_len == data_length1:
-
break
-
print(data1.decode('utf-8'))# 惰如磨刀之石
-
-
# 固定读取4字节
-
header2 = conn.recv(4)
-
data_length2 = struct.unpack('i', header2)[0] # 数据字节长度
-
-
data2 = conn.recv(data_length2) # 读取数据
-
print(data2.decode('utf-8')) # 不见其损,日有所耗
-
-
conn.close()
-
sock.close()
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgfcgei
系列文章
更多
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
怎样阻止微信小程序自动打开
PHP中文网 06-13