Python中asyncio.Protocol创建的TCP服务器为什么不存在粘包问题?
如题,测试了下,发现不会出现粘包的问题,可是没看懂是什么原因,求大神指导 🎈
Python中asyncio.Protocol创建的TCP服务器为什么不存在粘包问题?
不太可能,可能是你本地测的,没啥压力,没遇到而已, 网络不可能理解你的协议规则, 所以肯定是存在粘包的.
这个问题问得好,关键在于 asyncio.Protocol 的设计和 TCP 本身的特性。
首先,TCP 本身是流式协议,它只保证数据字节流的顺序,不维护消息边界。从这个角度看,“粘包”是TCP的固有特性,不是问题。所谓的“粘包”其实是应用层协议设计需要处理的事情。
asyncio.Protocol 不自动解决粘包,但它提供了清晰的事件驱动模型,让你能方便地实现自己的消息边界处理。核心方法是 data_received(data)。
当TCP数据到达时,data_received 会被调用,但传入的 data 是一个 bytes 对象,其长度是随机的,可能包含多条应用层消息,也可能只包含半条。处理粘包的责任完全交给了你。
举个例子,假设你的应用层协议是简单的“长度前缀法”(比如前4个字节是消息体长度):
import asyncio
import struct
class MyProtocol(asyncio.Protocol):
def __init__(self):
super().__init__()
self._buffer = b'' # 累积缓冲区
self._msg_len = None # 当前正在解析的消息长度
def data_received(self, data):
# 将新数据追加到缓冲区
self._buffer += data
# 循环处理缓冲区中完整的消息
while self._buffer:
# 如果还不知道消息长度,尝试读取长度头
if self._msg_len is None:
if len(self._buffer) < 4:
return # 数据不够,等待下次接收
# 读取4字节的长度头(网络字节序,大端)
self._msg_len = struct.unpack('>I', self._buffer[:4])[0]
self._buffer = self._buffer[4:] # 移除已处理的头
# 检查缓冲区是否有完整的消息体
if len(self._buffer) < self._msg_len:
return # 数据不够,等待下次接收
# 提取一条完整消息
message = self._buffer[:self._msg_len]
self._buffer = self._buffer[self._msg_len:] # 移除已处理的消息
self._msg_len = None # 重置,准备解析下一条消息
# 处理完整的应用层消息
self.handle_message(message)
def handle_message(self, message: bytes):
# 在这里实现你的业务逻辑
print(f"收到完整消息: {message.decode()}")
# 例如,回复一个响应
if self.transport:
self.transport.write(b"OK\n")
# 创建服务器
async def main():
loop = asyncio.get_running_loop()
server = await loop.create_server(MyProtocol, '127.0.0.1', 8888)
async with server:
await server.serve_forever()
if __name__ == '__main__':
asyncio.run(main())
总结:asyncio.Protocol 把TCP流式数据切块给你,但组装成应用层消息得自己写代码。
刚看了下源码,好像是它读写都有个缓冲区去处理信息
tcpdump 抓一波试试就知道了~
没到瓶颈,可能是单人测试环境,试下虚拟机跑脚本请求大量数据
每次看到有人提到粘包这个词,都挺烦的,5 楼帖子里民科说得好
也许开启了 NODELAY ?
因为你发的太慢了
在十几年前我搜索网络编程相关的文章,就被 CSDN 上的文章和帖子里的“粘包”这个民科概念误导过一阵子。
那个时候刚刚接触电脑,又没有读过网络编程相关的书,编程时既想要 UDP 的效果,又想要 TCP 的可靠,还想“简单”,同时明明知道先发送个数据长度或数据类型,亦或是使用分隔符就可以解决的问题,却不知道为什么就是不愿意这么做,然后就搜索相关解决办法看看别人怎么做的,然后就不幸看到“粘包”这个愚蠢的说法,还被误导了一阵子。
现在都 8102 年了,怎么现在还有人用这个民科概念,楼主该看看书更新更新脑子啦!
呃,楼里不少人该看看书更新更新脑子了。
tcp 没有所谓的“粘包”问题,本就是流式协议
哈啊哈
谢谢大家,现在总算弄明白了,tcp 是流式协议,需要自定义发|收包的协议才能正确通讯~
以前的人水平不行,不知道 TCP 是流式协议,以为在发送端 Write 什么,接收端的 Read 也会得到同样的数据,结果在发生合并或者分割的时候,就称之为“粘包”。所以“粘包”根本不是“问题”,问题在于不懂得在应用层做切分。
粘包半包也就是个说法 拿个词来黑没什么意思吧


