代码之家  ›  专栏  ›  技术社区  ›  Huckle

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

  •  0
  • Huckle  · 技术社区  · 6 年前

    我有一个服务器程序 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

    wsd

    1 回复  |  直到 6 年前
        1
  •  0
  •   Huckle    6 年前

    发布@n.m.所说的内容。如果他们将评论作为答案发布,则会记下:

    read 缓冲的 I/O功能。你已经放弃了所有的控制权。您不知道到底从底层文件描述符读取了多少字节。你可以试着用 setvbuf 使您的文件无缓冲区。n、 m。