python - 如何可靠地从 TCP 套接字中准确读取 n 个字节?
问题描述
语境:
二进制协议通常定义给定大小的帧。该struct
模块擅长解析,前提是所有内容都已在单个缓冲区中接收。
问题:
TCP 套接字是流。从套接字读取不能提供比请求更多的字节,但可以返回更少。所以这段代码不可靠:
def readnbytes(sock, n):
return sock.recv(n) # can return less than n bytes
天真的解决方法:
def readnbytes(sock, n):
buff = b''
while n > 0:
b = sock.recv(n)
buff += b
if len(b) == 0:
raise EOFError # peer socket has received a SH_WR shutdown
n -= len(b)
return buff
可能效率不高,因为如果我们要求大量的字节,并且数据如果非常碎片化,我们会反复重新分配一个新的字节缓冲区。
问题:
怎样才能可靠地从流套接字准确接收 n 个字节而没有重新分配的风险?
参考:
这些其他问题是相关的,并且确实给出了提示,但没有一个给出简单而明确的答案:
解决方案
解决方案是使用recv_into
和一个memoryview
. Python 允许预先分配一个可修改bytearray
的可传递给recv_into
. 但是您不能将数据接收到字节数组的切片中,因为切片将是一个副本。但是 amemoryview
允许将多个片段接收到同一个中bytearray
:
def readnbyte(sock, n):
buff = bytearray(n)
pos = 0
while pos < n:
cr = sock.recv_into(memoryview(buff)[pos:])
if cr == 0:
raise EOFError
pos += cr
return buff
推荐阅读
- json - 字典到 JSON 字符串
- python - Python:重采样和前向填充到最近一个月
- graph - 如何将表格导出为 png 文件?
- python - 无法从 JWT 导入 TokenObtainPairView、TokenRefreshView
- javascript - 如何让 Chrome 扩展程序休眠一段时间并在端口上发布消息
- python - 优化大型excel文件的处理
- javascript - 如何使用javascript为每个表行打印不同的值
- ide - Liferay Cloud IDE,多个开发人员在同一个 liferay 服务器上工作
- php - Laravel 将退出状态代码任意设置为自定义命令
- ios - 旋转图像后缺少缩放