我有一个服务器程序
select
呼叫信号,有输入读取,服务器将读取和处理多达1K的数据。如果要发送响应,它将发送响应。然后它会回到
选择
.
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字节的小挂断信息。
选择
应该是有用的。客户机发送的消息小于读取缓冲区,因此服务器读取整个内容并做出响应。然后客户机发送3K消息。服务器读取第一个1K,然后读取后续1K
呼叫超时。我预料到了
选择
如果内核为该文件描述符缓冲了数据,则立即返回并发出数据可用的信号。客户端超时后,它会发送一条挂断消息。当挂断消息到达时,服务器突然能够
选择
我非常确定这些事件的时间安排,因为(1)涉及长时间超时,(2)会话的tcpdump确认3K消息作为单个TCP段到达。
一个简单的演示程序使用
pipe
不会显示此行为,也不会显示另一个使用TCP套接字的简单演示。所以我一定在服务器程序里做了些傻事。我应该检查什么?
-
客户机的read FD位于select之前的read FD集合中
-
客户端的read FD是否在select之后的read FD集合中(不是)
-
-
是否再次致电
fread
会阻塞(不会。我在调试器中尝试过,我也用
recv_buffer
大小为4K,读取整个3K消息)
-
数据包碎片(无)通过
tcpdump