根据the POSIX poll docs,POLLOUT
标志表示"正常数据可以不受阻塞地写入。"。但是有多少数据?有没有固定的保证,或者有什么方法可以找出有多少缓冲空间?
我写信给管道和插座。一般情况下,我的计划不会获得EINTR
,因为所有预期的信号都是通过signalfd
/ kqueue
处理的;据我所知,这意味着我可以期待write
始终阻止,直到所有请求的数据都被传输完毕。
我不确定我是否想要这个。理想情况下,我只想编写与缓冲区中的空间一样多的数据,以便代码可以在不阻塞的情况下尽快返回到轮询循环。 (如果有,那么数据仍然可以写入,我的代码可以再次在同一个FD上检查POLLOUT
,并在空间可用时再次执行相同的操作。)
有没有办法让这项工作顺利进行? poll
似乎可以很好地从阻塞管道/套接字FD中读取:当设置POLLIN
标志时,您会读入一个缓冲区,并且可以获得尽可能多的阻塞。但它开始看起来有点不方便写作!我错过了什么吗?
或者这只是试图告诉我使用O_NONBLOCK
?
我正在使用OS X和Linux。
答案 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()调用将继续返回“写入更多数据!”。