【问题标题】:Why use writefds in select ? How to use them in practice?为什么在 select 中使用 writefds?如何在实践中使用它们?
【发布时间】:2013-12-03 00:35:19
【问题描述】:

我正在 linux 中设计一个 C 程序,其中有两个线程。一个主线程是执行主函数处理的 event_processor_thread。第二个线程是一个始终在后台运行的 event_dispatcher 线程,实时读写多个接口(非阻塞异步 i/o)

我在网上做了一些研究,发现实现non-blocking socket i/o的最好方法可以通过

  1. libevent
  2. select()

我选择了后者,因为它更容易,而且我最多有 4 个接口可以读取/写入。

我很清楚使用readfds 的听/读机制,但我不确定如何使用writefds!如果我将我的数据从 event_processor_thread 放到共享内存中,并让这个事件调度线程从共享内存中读取它并使用send() 写入,那么 select 是否会自行将数据发送到套接字?这就是我需要在select() 中使用writefds 的原因吗?

如果我的问题不清楚,我深表歉意,我基本上想要的是有一个非阻塞 i/o 线程来将事件发送到事件处理器线程或从事件处理器线程发送到外部接口。高度赞赏这方面的任何投入。谢谢!

【问题讨论】:

标签: c linux multithreading sockets select


【解决方案1】:

select 的 writefds 是检查文件描述符是否准备好写入。对于一个套接字,这意味着与该套接字关联的发送缓冲区未满。

假设您平台上的套接字有一个 8 kb 的缓冲区,而您要发送 100 kb 的数据。

您调用write 并获得返回值 8192,表示前 8192 个字节已被写入。下一次 write 调用返回 EAGAINEWOULDBLOCK,表示发送缓冲区已满。

您现在可以使用select 再次查找发送缓冲区何时有空间(即何时向客户端传输了一个 tcp/ip 数据包),以便您继续写入。同时,您可以监听新连接并等待来自客户端的输入。

注意select从不发送任何数据,它只是同时监控几个文件描述符的状态。

【讨论】:

    【解决方案2】:

    不,select() 不会“照顾写作”。当 writefds 集中包含的一个或多个文件描述符变为可写时,它将通知您。这可能意味着有问题的 fd(s) 已经完成了您之前执行的(非阻塞)写入,因此您现在可以执行另一个操作。

    【讨论】:

    • 感谢 unwind 和@Klas Lindback,你的意思是说我应该实现这样的事情:1. 写入套接字 2. 如果写入的字节数未满,请尽快返回,3. 选择() 如果套接字准备好写入,将发送通知 4. 将剩余数据写入套接字
    • @vinit:是的,这是select()writefds 参数的用例之一(尽管当写入的字节数“未满”时您不会停止,但您当send()/write() 告诉您停止时停止,因为发生了EAGAINEWOULDBLOCK 错误)。另一个用例是检测非阻塞connect() 何时成功。
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2011-11-14
      • 1970-01-01
      • 2020-07-09
      • 2011-08-06
      • 2012-04-17
      • 1970-01-01
      • 2021-01-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多