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 套接字)

TCP 套接字上的 send() 是不是可以返回 >=0 和 <length?

检测 TCP 何时拥塞 python 扭曲套接字服务器

TCP套接字服务器如何判断从客户端接收到的数据何时完成?

客户端 read() 获取消息的随机尾随字符(使用套接字的 TCP 客户端-服务器)