何时使用poll C函数的POLLOUT事件?

15

我使用 socket() + POLLIN poll() + recv() + send() 写了一个小型 TCP 服务器,但我不知道何时使用 POLLOUT poll 或 select 的 writefds 来轮询可写事件。

有人能给我一个关于 POLLOUT 的实际使用示例吗?


通常这不是一种安全的方法;) - Shawn
@Shawn,为什么POLLOUT不安全? - xiaochen
3个回答

29
通常的模式是使用非阻塞文件描述符和poll()一起使用,具体如下:
  • 在准备调用poll()之前,
    • 始终设置POLLIN,因为您总是想读取套接字另一端发送给您的内容。
      • 除非存在大量的传入数据积压,并且您有意让对方等待发送更多数据。
    • 只有在需要向对方发送未完成的数据时才设置POLLOUT
  • poll()返回后,如果它指示可读取数据,
    • 读取并处理它
  • poll()返回后,如果它指示套接字可写,
    • 尝试发送未完成的数据。
      • 如果您成功地发送了所有数据,则下次循环不会再设置POLLOUT
      • 如果您只能发送其中的一部分(或没有),则将其余部分保留到以后。您将在下次循环时设置POLLOUT
  • 当您有新数据要发送(无论是响应于您读取的数据还是响应于某个外部事件),您有两个选择:
    • 立即尝试发送其中的一部分。您可能无法成功地发送任何数据,某些数据或全部数据。与前一个情况一样,保留未写入的数据部分并计划仅当有数据剩余时在下次循环中设置POLLOUT
    • 只需保留数据并计划在下次循环中设置POLLOUT。(这种选择通常更容易编程,因为您只需要在循环的一个位置处理写数据,但另一方面它将延迟写数据直到下次循环。)

2
+1 是因为详细的流程描述,因为很少有好的 POLLOUT 示例。 - laindir
“POLLHUP” 不应由调用方设置。如果内核检测到套接字已关闭(连接丢失),则会设置它。 - Alexis Wilke
@AlexisWilke 感谢您的更正。我自己对于 POLLHUP 从来没有非常确定,所以想设置它“只是为了确保”。 - Celada

1

从nginx源代码中,我发现:

如果有一些数据要发送,nginx会尝试使用系统调用(可能是writev)进行发送。然而,如果nginx无法一次性发送所有数据,则会在pollfd上设置POLLOUT(如果使用poll事件),以等待可写事件。当获取到可写事件时,nginx将发送剩余的数据。

当nginx尝试响应大型静态文件时,很容易重现这种情况。


0

使用c++ 98和gcc在Raspberry PI 3上的Debian上工作...

在Acceptor/Connector模式和Reactor/Proactor/ACT模式的实现中,我经常按以下顺序使用POLLOUT:

  1. 使用socket函数打开套接字。
  2. 使用fcntl将套接字文件描述符设置为非阻塞模式。
  3. 调用connect并检查返回代码。

在大多数情况下,connect返回-1。由于非阻塞文件描述符,这是非常可能的。然后我检查结果代码。

如果是EINPROGRESS,则在反应器(使用ppoll或epoll)中注册一个事件处理程序,并使用POLLOUT。当连接最终完成时,poll会返回POLLOUT。

然后我创建一个新的TcpConnection类并进行通信。


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