我有一个服务器程序,该服务器程序使用select
且超时时间为10秒,以等待几个非阻塞客户端连接上的活动。每次select
呼叫表示有要读取的输入时,服务器将读取并处理多达1K的数据。如果有要发送的响应,它将发送它。然后它将返回到select
。
fcntl(clientFd, F_SETFL, fcntl(clientFd, F_GETFL, 0) | O_NONBLOCK);
while (true) {
FD_ZERO(&readfds);
FD_SET(clientFd, &readfds);
timeout = (struct timeval){.tv_sec = 10};
select(clientFd + 1, &readfds, NULL, NULL, &timeout);
if (FD_ISSET(clientFd, &readfds)) {
uint8_t recv_buffer[1024];
fread(recv_buffer, 1, 1024, clientFile);
// process & maybe respond / fflush
}
}
客户端消息的范围从小(10或100字节)消息到大(3-10K消息)。客户在挂断电话之前,最多需要等待30秒才能得到答复。挂断电话时,他们会发送一条10字节的挂断消息。
一个正在发挥作用的场景正在打破我对select
应该如何工作的理解。客户端发送的消息小于读取缓冲区,因此服务器读取整个消息并作出响应。然后,客户端发送3K消息。服务器读取第一个1K,然后随后的select
呼叫超时。我期望select
立即返回并发出信号,如果内核为该文件描述符缓冲了数据,则表明有可用数据。客户端超时后,它将发送挂断消息。当挂断消息到达时,服务器突然可以select
那个文件描述符,并读取客户端较大消息的第二和第三块,然后读取客户端较小消息。
我非常确定这些事件的发生时间,原因是:(1)所涉及的超时时间长,(2)会话的tcpdump确认3K消息作为单个TCP段到达。
使用pipe
的简单演示程序不会表现出这种现象,使用TCP套接字的另一个简单演示也不会表现出来。因此,我必须在服务器程序中做一些愚蠢的事情。我应该检查什么?
我正在检查:
fread
的调用(没有。我在调试器中尝试过,我还对大小为4K的recv_buffer
进行了另一次运行,以读取整个3K消息) tcpdump
的数据包分段(无)
答案 0 :(得分:0)
发布@ n.m。说过。如果他们发表评论作为答案,将会删除:
read
是缓冲 I / O功能。您已经放弃了所有控制权。您不知道从底层文件描述符中实际读取了多少字节。您可以尝试使用setvbuf
来使文件无缓冲。 – n.m.