如何判断套接字缓冲区是否已满?

Cra*_*enz 13 c sockets

如何判断读取套接字缓冲区是否已满或写入套接字缓冲区是否为空?

有没有办法在没有系统调用的情况下获得套接字缓冲区的状态?

更新:怎么样:当读取套接字缓冲区已满或写入套接字缓冲区为空时,我想获得回调或信号.这样我就可以停止处理以允许在线路上发生更多的I/O,因为在线路上发送数据时,I/O限制总是一个问题.

select()电话是你如何检查是否读缓冲区中有一些东西.不是当它满了(我想).

caf*_*caf 12

轮询文件描述符select并使用零超时 - 如果select表示它是可写的,则发送缓冲区未满.

(哦...... 没有系统调用.不,没有.)

附录:

为了响应您更新的问题,您可以ioctl在TCP套接字上使用两个s:SIOCINQ返回接收缓冲区中未读数据SIOCOUTQ的数量,并返回发送队列中未发送数据的数量.我不相信这些有任何异步事件通知,这将让你不得不轮询.


小智 12

我知道这是一个老线程,但为了那些通过搜索引擎偶然发现的人的利益,我将回答这个问题,因为它上面没有真正回答过.

在开始之前,克服系统调用挂断 - 您无法在不切换内核空间的情况下与基于内核的(*nix)网络堆栈进行交互.您的目标应该是了解堆栈功能,以便您可以充分利用系统.

如何判断读取套接字缓冲区是否已满

这部分已经回答了 - 你没有回答,因为这不是你应该怎么想的.

如果发送者(严重)将其分段为TCP帧(通常是由于未在输出上缓冲封送数据,并且使用TCP_NDELAY关闭Nagle算法),那么减少系统调用次数的想法是个好主意.您应该使用的方法涉及设置"低水位线"进行阅读.首先,通过使用setsockopt()设置SO_RCVBUF,建立您认为合理的接收缓冲区大小.然后使用getsockopt()读回实际的读取缓冲区大小,因为您可能无法得到您要求的内容.:)不幸的是,并非所有实现都允许您再次阅读SO_RCVBUF,因此您的里程可能会有所不同.接下来,在您想要阅读之前,确定您想要阅读的数据量.使用setsockopt()设置此大小的SO_RCVLOWAT.现在,套接字的文件描述符只有在读取至少读取的数据量时才会选择为可读.

或写入套接字缓冲区为空?

这是一个有趣的一个,因为我需要做到这一点最近,以确保我的MODBUS/TCP ADU的各自占据自己的TCP帧,其中MODBUS规范要求(@steve:控制碎片是一个时间,你需要知道发送时缓冲区是空的!).就原始海报而言,我非常怀疑他是否真的想要这个,并且相信在他开始之前知道发送缓冲区大小会更好,并且在发送期间定期检查发送缓冲区中的数据量,使用已经描述的技术.这将提供关于所使用的发送缓冲区的比例的更精细的信息,这可以用于更顺利地节省生产.

对于那些仍然对如何检测(异步)发送缓冲区为空(一旦你确定它真的是你想要的)感兴趣的人,答案很简单 - 你设置发送低水位线(SO_SNDLOWAT)等于发送缓冲区尺寸.这样,当发送缓冲区为空时,套接字的文件描述符将仅选择为可写.

我对你的问题的回答都围绕着select()的使用,这并非巧合.在几乎所有情况下(我意识到我现在正在进入宗教领域!)需要移动大量数据(内部和主机间)的应用程序最好构造为单线程状态机,使用选择掩码和基于pselect()的处理循环.如今,一些操作系统(Linux命名之一)甚至允许您使用文件描述符选择来管理信号处理.什么奢侈 - 当我还是个男孩的时候...... :)

彼得


Ste*_*sop 11

你可以试试ioctl.FIONREAD告诉您可以立即读取多少字节.如果这与缓冲区大小(您可以通过另一个icotl调用检索和/或设置)相同,则缓冲区已满.同样,如果您可以写出与输出缓冲区大小一样多的字节,那么输出缓冲区为空.

我没有广泛支持FIONREAD,FIONWRITE和SIOCGIFBUFS(或等价物).我不确定我曾经使用过任何一种,虽然我有一种偷偷摸摸的感觉,我出于某种原因在Symbian上使用了类似的功能.

调用是否需要内核模式来计算它是特定于平台的.模糊地试图避免系统调用不是一种有效的优化技术.

一个基本的BSD风格的套接字接口没有提到任何关于读写缓冲区的内容.什么时候发送缓冲区是否为空是否重要?它当然并不意味着已经在套接字的另一个端点接收到所有数据 - 它可能位于某个路由器的某个地方.同样,"你的"读缓冲区已满,并不能保证另一端的写操作会阻塞.

一般来说,您只需尽可能多地读/写,并让套接字层处理复杂性.如果你看到很多I/O都是用小尺寸完成的,那么可能存在一些性能问题.但请记住,流套接字将一次发送/接收一个包,其中包含一个数据块.除非设置了TCP_NODELAY,否则不会像NIC上的字节到达字节那样,并且最终可能会为每个字节进行一次读取调用.它们是以数据包形式到达的,因此很可能一次性可读,也许一次只能达到1k-ish.你不太可能通过推迟阅读来加快速度,直到有很多东西需要阅读.实际上,您可能会使情况变得更糟,因为当您的端点的读取缓冲区已满时,存在传入数据被丢弃的风险,因为无处存储它,导致延迟和重新发送.