我正在尝试使用 Unix 域套接字接收几兆字节的数据。我的问题是接收到的数据总是在 219,264 字节处截止。收到该金额后,我可以继续发送,但是在完全重置连接之前我无法接收任何内容。我的代码和最小示例(假设套接字定期发送数据)如下。
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect(f"{socketpath}")
data = b""
while True:
received = s.recv(1024)
data += received
print("Received some data")
while True:
sock.send(b"{a JSON-RPC string}")
服务器端是
go-ethereum
。接收也不例外(只是在调用 recv
时挂起),发送时,一旦总共发送了 219264 个字节,就会抛出 in s.send(...) OSError: [Errno 32] Broken pipe
。另外,一旦我开始收到 Broken pipe
,recv
就会开始响应,但总是返回空结果 (b''
)。
*现在似乎也发生在 36544 字节上。完全随机的两者之一。
观察到的行为来自于达到 IPC 的缓冲区限制。当尝试写入大量数据或超过 IPC 缓冲区大小时,写入将无法完成并向套接字写入 EOF。 recv 调用正在读取所有这些数据,等待 EOF 返回。然后你就会陷入僵局。
这是使用 AF_UNIX 套接字时当前操作系统的限制。当使用带有 AF_UNIX 套接字的套接字对时,您可以看到类似的行为。如果设置了 MSG_DONTWAIT 标志(在发送调用上),检查返回值的小型 C 程序将出错并返回 EWOULDBLOCK。
这里有一篇很棒的文章:ipc buffers。经验表明,准确的字节数 219264 是本文中特定 Linux 系统的限制。
解决方案有多种选择。一种选择是发回少量数据并在接收端将其组装。第二个是检查此限制并执行某种错误处理。另一个方法是不使用 Unix 域套接字并接受网络协议 (TCP/IP) 的开销。第四个选项是实现一些并发性,以确保读取器和写入器不在同一进程中。还有其他解决方案,但这应该为其他人提供快速解决方案。