POSIX POLLOUT和阻止文件描述符

时间:2016-02-05 02:16:44

标签: sockets pipe posix polling

根据the POSIX poll docsPOLLOUT标志表示"正常数据可以不受阻塞地写入。"。但是有多少数据?有没有固定的保证,或者有什么方法可以找出有多少缓冲空间?

我写信给管道和插座。一般情况下,我的计划不会获得EINTR,因为所有预期的信号都是通过signalfd / kqueue处理的;据我所知,这意味着我可以期待write始终阻止,直到所有请求的数据都被传输完毕。

我不确定我是否想要这个。理想情况下,我只想编写与缓冲区中的空间一样多的数据,以便代码可以在不阻塞的情况下尽快返回到轮询循环。 (如果有,那么数据仍然可以写入,我的代码可以再次在同一个FD上检查POLLOUT,并在空间可用时再次执行相同的操作。)

有没有办法让这项工作顺利进行? poll似乎可以很好地从阻塞管道/套接字FD中读取:当设置POLLIN标志时,您会读入一个缓冲区,并且可以获得尽可能多的阻塞。但它开始看起来有点不方便写作!我错过了什么吗?

或者这只是试图告诉我使用O_NONBLOCK

我正在使用OS X和Linux。

2 个答案:

答案 0 :(得分:1)

从表面上看,你保证能够写的最多是1个字节。

切换到非阻塞模式也无助于改善。当然,你不会阻止,但你必须弄清楚如何处理非阻塞写入没有写入的任何数据。无论文件描述符的阻塞模式如何,poll()都会给出相同的结果。

您可以尝试一些替代方案,异步IO或ZeroMQ等框架。

异步IO

asynchronous IO,它有效地归结为让一堆后台线程为你写作。这没关系,但是你必须管理数据生命周期/所有权问题。您必须保留正在编写的内容并保持不变,直到您被告知异步写入完成为止。至少可以这么说。

<强>框架

另一个选项是消息框架,例如ZeroMQ。还有其他人 - nanomsg(由同一个人做ZeroMQ),DDS,Corba(如果你敢),TASTE来自ESA等。

放弃替换

这些都具有不同的品质,但ZeroMQ和nanomsg特别设计为将代码从使用标准套接字和管道API转换为使用自己的(特别是nanomsg)的最痛苦的方式。

消息,而不是Streams

所有这些都是面向消息的,而不是面向流的,并且它们都能很好地管理通过某种连接传递数据的痛苦业务,并解决数据生命周期问题。

基础传输

ZeroMQ和nanomsg将跨管道,套接字,共享内存等工作。当代码等待输入时,它们也可以在其poll()的等效项中包含普通文件描述符(如果你有,比如说,有用的话) fd也是串口侦听的。)

与异步IO的比较

此类框架与async io之间的区别如下。使用框架,连接另一端的软件也必须使用相同的框架,否则无法进行通信。使用aio,另一端仍然可以使用普通的同步套接字函数调用,因为从根本上它仍然只是一个流连接。

框架比aio更不透明。谁知道框架内部正在进行多少数据复制?这通常无关紧要,假设您的RAM比您的网络快得多。

0MQ / nanomsg与其余

ZeroMQ / nanomsg与DDS / Corba / TASTE之类的区别在于后者还包含序列化。它们允许您以独立于平台的描述语言指定消息结构,该语言可以“编译”为您正在使用的任何源代码语言(C,C#,JAVA等)。这很自然,有点像声明C结构。这允许您在连接的另一端拥有完全不同的平台和编程语言,并且它们仍然可以通话。 DDS和Corba为此使用IDL,TASTE使用ASN.1(这在所有方面都是优越的)但是TASTE有点难以实现。

通过使用Google协议缓冲区或ASN.1(或任何many available)来序列化数据和ZeroMQ / nanomsg来传输由ZeroMQ / nanomsg生成的字节流,您可以使用ZeroMQ / nanomsg实现相同的效果序列化器作为消息。

答案 1 :(得分:1)

唯一的保证是你可以写至少1个字节;但是,通常会更多,因为大多数操作系统都很聪明,以避免silly window syndrome

  

我不确定我是否想要这个。理想情况下,我想写尽可能多的数据   因为缓冲区中有空间,所以代码可以返回   轮询循环尽快而不阻塞。

然后使用O_NONBLOCK。对套接字的write()将返回写入内部缓冲区的字节数。如果你尝试写入10,000个字节而write()返回2,000,那么你还剩下8,000个字节。它需要更多的内部管理(好吧,一个指针和一个整数),但它是保持内核缓冲区满的最有效方法。

请注意,如果您已完成写入,请清除events标志中的位或您的poll()调用将继续返回“写入更多数据!”。