IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> python网络编程粘包处理 -> 正文阅读

[网络协议]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()

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-01-24 11:18:35  更:2022-01-24 11:20:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年10日历 -2024/10/5 9:26:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码