为什么select不能用缓冲数据向文件描述符发送信号?

时间:2019-02-03 23:01:39

标签: c select linux-kernel posix nonblocking

我有一个服务器程序,该服务器程序使用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套接字的另一个简单演示也不会表现出来。因此,我必须在服务器程序中做一些愚蠢的事情。我应该检查什么?

我正在检查:

  • 客户端的读取FD位于选择之前的读取FD集中
  • 选择后(不是)客户端的读取FD是否位于读取FD集中
  • 读取数据的大小(如果至少有那么多可用,则始终为1K)
  • 是否再次阻塞对fread的调用(没有。我在调试器中尝试过,我还对大小为4K的recv_buffer进行了另一次运行,以读取整个3K消息)
  • 通过tcpdump的数据包分段(无)

wsd

1 个答案:

答案 0 :(得分:0)

发布@ n.m。说过。如果他们发表评论作为答案,将会删除:

  

read缓冲 I / O功能。您已经放弃了所有控制权。您不知道从底层文件描述符中实际读取了多少字节。您可以尝试使用setvbuf来使文件无缓冲。 – n.m.