TCP 套接字上的 read() 何时返回
Posted
技术标签:
【中文标题】TCP 套接字上的 read() 何时返回【英文标题】:When does a read() on a TCP socket return 【发布时间】:2016-08-30 06:07:15 【问题描述】:有人可以解释一下,我用来从 TCP 套接字获取数据的读取函数何时返回?
我使用下面的代码从测量系统中读取数据。该系统以 15 Hz 的频率提供数据。 READ_TIMEOUT_MS
的值为 200
此外READ_BUFFER_SIZE
的值为40000
。
一切正常,但发生的情况是,read()
每秒返回 15 次,读取 1349
字节。
通过阅读以下文档中的陷阱 5,我预计缓冲区已被完全填满:
http://www.ibm.com/developerworks/library/l-sockpit/
初始化:
sock=socket(AF_INET, SOCK_STREAM, 0);
if (socket < 0)
goto fail0;
struct sockaddr_in server;
server.sin_addr.s_addr = inet_addr(IPAddress);
server.sin_family = AF_INET;
server.sin_port = htons(Port);
if (connect(sock,(struct sockaddr *)&server, sizeof(server)))
goto fail1;
struct timeval tv;
tv.tv_sec = READ_TIMEOUT_MS / 1000;
tv.tv_usec = (READ_TIMEOUT_MS % 1000) * 1000;
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)))
goto fail1;
return true;
fail1:
close(sock);
sock = -1;
fail0:
return false;
阅读:
unsigned char buf[READ_BUFFER_SIZE];
int len = read(sock, buf, sizeof(buf));
if (len <= 0)
return NULL;
CBinaryDataStream* pData = new CBinaryDataStream(len);
pData->WriteToStream(buf, len);
return pData;
我希望这个问题不是重复的,因为我在问之前已经搜索了答案。 如果您需要更多信息,请告诉我。
【问题讨论】:
只要您的操作系统喜欢它,它就会返回。您必须准备好获得比您想要的更少的字节。陷阱 5 实际上暗示了这一点。该图显示了 1024 个字节的读取,但文本谈到它返回 200 个字节。 您可能需要查看select
以获得更容易控制的超时。
@n.m.:我理解操作系统的这种行为。但我想知道为什么read()
的调用每次都会返回所需的字节数。
我不明白你想说什么。如果您要求读取 N 个字节,则可以得到 0 到 N 个字节的任意值。对前面的句子有疑问吗?
【参考方案1】:
我怀疑您使用的是 Linux。 manpage for read says:
成功时,返回读取的字节数(零表示结束 文件),并且文件位置由这个数字提前。它不是 如果此数字小于请求的字节数,则会出错;
TCP 套接字模拟字节流,而不是面向块或面向消息的协议。如果应用程序的缓冲区中有任何可用数据,则在套接字上调用 read 会返回。原则上,数据到达网卡,然后传输到内核空间,由内核和网络堆栈处理。最后,read
系统调用从内核空间获取数据并将其传输到用户空间。
从套接字读取时,您必须期望可以读取任意数量的字节。只要读取缓冲区中有任何内容或发生错误,对 read 的调用就会返回。您无法预测或假设有多少字节可用。
此外,由于操作系统已中断,调用可以返回而不读取任何内容。这在调试或分析您的应用程序时经常发生。你必须在你的应用层处理这个。
当您希望获得高数据速率或低延迟时,完整的接收器路径会非常复杂。内核和 NIC 实现了许多优化,例如将负载分散到内核上,增加局部性并将处理卸载到 NIC。以下是一些您可能会感兴趣的附加链接:
https://www.lmax.com/blog/staff-blogs/2016/05/06/navigating-linux-kernel-network-stack-receive-path/ https://blog.cloudflare.com/how-to-achieve-low-latency/ http://blog.packagecloud.io/eng/2016/06/22/monitoring-tuning-linux-networking-stack-receiving-data http://syuu.dokukino.com/2013/05/linux-kernel-features-for-high-speed.html【讨论】:
感谢您的回答!是的,我正在使用 Linux 平台。您说“只要读取缓冲区中有任何内容,就会调用读取返回。”这是否意味着read()
返回的字节在我的情况下出于任何原因简单地“匹配”?
@bushmills 有很多网站描述了从 NIC 到应用程序的漏洞路径,例如cubrid.org/blog/dev-platform/understanding-tcp-ip-network-stack.
@bushmills 是的,调用 read 可以获得任意数量的字节,最多可达提供的最大值。它可以 1.您必须在应用程序中实现自己的框架,例如通过循环读取,直到收到消息的预期字节数。
我实现了框架以获取测量系统发送的所有数据。由于一切正常,这不是问题。我只是想知道,为什么我每次都得到所需的字节数,即使这也不能保证。
@bushmills 我添加了更多链接,这些链接描述了接收器部分以及内核和 NIC 的优化。以上是关于TCP 套接字上的 read() 何时返回的主要内容,如果未能解决你的问题,请参考以下文章
c#SslStream的read()函数如何知道何时返回0?
如何检测 TCP 套接字断开连接(使用 C Berkeley 套接字)