TCP套接字上的read()函数什么时候会返回?

5
请问,当我使用用于从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个字节。 - n. m.
你可能想要查看select,以获得更易于控制的超时。 - user4581301
@n.m.:我理解操作系统的这种行为。但是我想知道为什么每次调用read()都会返回所需的字节数。 - bushmills
我不明白你想说什么。如果你要求读取N个字节,你可能会得到从0到N个字节的任何数量。前面那句话有问题吗? - n. m.
1个回答

2
我怀疑您正在使用Linux。read命令的manpage中说:
当成功时,返回读取的字节数(零表示文件结尾),并且文件位置将按此数字向前移动。如果此数字小于请求的字节数,则不是错误;
TCP套接字模拟字节流而不是块或消息定向协议。在套接字上调用read,如果应用程序的缓冲区中有任何数据可用,则返回。原则上,数据到达网络卡后,然后转移到内核空间,在那里由内核和网络堆栈处理。最后,read系统调用从内核空间获取数据并将其传输到用户空间。
从套接字读取时,您必须预期可以读取任意数量的字节。调用read会在读取缓冲区中有任何内容或发生错误时立即返回。您无法预测或假设可能可用多少字节。
此外,调用可能在未读取任何内容的情况下返回,因为操作系统已被中断。当调试或分析应用程序时,这经常发生。您必须在应用程序层面处理这种情况。
完整的接收路径在需要高数据速率或低延迟时会变得非常复杂。内核和网卡实施了许多优化,例如将负载分散到各个核心,增加局部性并将处理卸载到网卡上。以下是一些你可能会感兴趣的附加链接:

谢谢您的回答!是的,我正在Linux平台上工作。您说:“调用read会在读取缓冲区中有任何内容时立即返回。”这是否意味着read()返回的字节仅仅是因为某种原因与我的情况“匹配”? - bushmills
1
@bushmills,有很多网站描述从网络接口卡到应用程序的整个路径,例如http://www.cubrid.org/blog/dev-platform/understanding-tcp-ip-network-stack/。 - Jens
@bushmills 是的,调用read可以获取最多提供的任意数量的字节。这可能会发生。2.您必须在应用程序中自己实现帧,例如通过循环读取直到接收到消息所需的预期字节数。 - Jens
我实现了帧结构以获取测量系统发送的所有数据。由于一切正常,这不是问题。我只是想知道为什么每次都能得到所需的字节数,即使这并不保证。 - bushmills
1
@bushmills 我增加了一些链接,描述了接收器部分以及内核和网络适配器的优化。 - Jens
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接