为什么在select中要使用writefds?如何在实践中使用它们?

6

我正在Linux中设计一个C程序,其中将有两个线程。一个主线程是event_processor_thread,用于执行主要功能处理。第二个线程是event_dispatcher线程,始终在后台运行,实时写入和读取多个接口(非阻塞异步I / O)。

我在互联网上进行了一些研究,并发现实现非阻塞套接字I / O的最佳方法可以通过:

  1. libevent
  2. select()

我选择了后者,因为它更容易,并且我最多只需要从/写入4个接口。

我清楚使用readfds进行监听/读取机制,但我不确定如何使用writefds!如果我将来自event_processor_thread的数据放入共享内存中,并使此事件分派程序线程从共享内存中读取并使用send()写入,那么select会自动发送数据到套接字吗?这就是为什么我需要在select()中使用writefds的原因吗?

如果我的问题不够清晰,我很抱歉。我想要的基本上是一个非阻塞I/O线程,用于将事件从/到事件处理线程分派到外部接口。对此方面的任何输入都将不胜感激。谢谢!


你会如何实现一个基本的事件循环?https://dev59.com/YHRB5IYBdhLWcg3wUV1d - HAL
请注意,libevent方法更适用于不同平台。 - Ztyx
3个回答

14

在 select 函数中,writefds 参数用于检查文件描述符是否准备好写入。对于一个套接字而言,这意味着与套接字相关联的发送缓冲区不是满的。

假设您的平台上的套接字具有 8kb 的缓冲区,并且您想发送 100kb 的数据。

您调用 write 函数并获得返回值 8192,表示已经写入了前 8192 个字节。随后的 write 调用将返回 EAGAIN 或者 EWOULDBLOCK,表明发送缓冲区已满。

现在,您可以使用 select 函数来找出何时再次有空间在发送缓冲区中(即当一个 TCP/IP 包已传输到客户端),以便您可以继续写入。同时,您也可以监听新连接并等待来自客户端的输入。

请注意,select 函数不会发送任何数据,它只是监视多个文件描述符的状态。


2
不,“select()”不会“处理写入”。它将在写入fds集包含的一个或多个文件描述符变为可写时通知您。这可能意味着问 题中的fd已完成你之前(非阻塞)的写入操作,这样你就可以进行另一个写入操作了。

感谢 unwind 和 @Klas Lindback,您的意思是我应该实现类似这样的东西:1. 写入套接字 2. 如果写入的字节数不足,则尽快返回 3. 如果套接字准备好写入,则 select() 将发送通知 4. 将剩余数据写入套接字。 - vinit
@vinit:是的,这是select()函数中writefds参数的一个用例(尽管您不会在写入的字节数“不足”时停止,而是在send()/write()告诉您因为发生EAGAINEWOULDBLOCK错误而停止时停止)。另一个用例是检测非阻塞connect()成功的情况。 - Remy Lebeau

2

select()函数告诉你文件描述符是否可写。对于套接字而言,这意味着可以在不阻塞调用者的情况下接受新的出站数据。如果你调用send()write(),但套接字的出站缓冲区已满,则会收到一个EAGAINEWOULDBLOCK错误,此时你应停止向该套接字写入数据,直到它再次变为可写状态。在非阻塞connect()调用后,select()还可以告诉你套接字何时变为可写状态,表示已成功建立连接并可以开始向对等方写入数据。


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