如何判断读套接字缓冲区是满的还是写套接字缓冲区是空的?
有没有一种不用系统调用就可以获得套接字缓冲区状态的方法?
更新:如果读套接字缓冲区已满或写套接字缓冲区为空,我希望得到一个回调或信号。这样,我就可以停止处理,以便在线路上出现更多的I/O,因为在线路上发送数据时,I/O绑定始终是一个问题。
select()
调用是如何检查读取缓冲区中是否包含某些内容的。当它满的时候(我想)是不会的。
发布于 2009-11-26 19:08:10
你可以试试ioctl
。FIONREAD告诉您有多少字节可以立即读取。如果这与缓冲区大小相同(您可能可以通过另一个icotl调用检索和/或设置缓冲区大小),则缓冲区已满。同样,如果可以写入与输出缓冲区大小相同的字节,则输出缓冲区为空。
我不知道FIONREAD、FIONWRITE和SIOCGIFBUFS (或同等功能)的支持有多广。我不确定我是否使用过其中的任何一个,虽然我有一种鬼鬼祟祟的感觉,我已经在Symbian上使用了类似的功能,或者其他原因。
调用是否需要内核模式来计算,这是特定于平台的。模糊地试图避免系统调用不是一种有效的优化技术。
一个基本的BSD风格的套接字接口对读和写缓冲区没有太大的帮助。发送缓冲区是否为空有什么关系?当然,这并不意味着所有的数据都是在套接字的另一个端点接收到的--它可能位于某个路由器的某个位置。同样,“您的”读取缓冲区已满并不能保证另一端的写入将被阻塞。
一般来说,您只需尽可能多地读/写,并让套接字层处理复杂性。如果您看到大量的I/O以微小的尺寸完成,那么可能存在一些性能问题。但是请记住,流套接字将一次发送/接收一个数据包,其中包含一个数据块。除非设置了TCP_NODELAY,否则字节并不是由NIC中的字节到达的,您可能会以每个字节进行一个读取调用而结束。它们是以数据包的形式到达的,因此很可能一次就会变得可读性很强,一次可能只有1k左右。除非有很多东西可读,否则你不太可能通过推迟阅读来加快速度。实际上,您可能会使情况变得更糟,因为当端点的读取缓冲区已满时,传入的数据可能会被丢弃,因为没有地方存储这些数据,从而导致延迟和重新发送。
发布于 2009-11-26 11:49:08
使用select
和零超时轮询文件描述符--如果select显示它是可写的,那么发送缓冲区就没有满。
(哦.没有系统呼叫。不,没有。)
增编:
针对您更新的问题,您可以在TCP套接字上使用两个ioctl
:SIOCINQ
返回接收缓冲区中未读的数据量,SIOCOUTQ
返回发送队列中未发送的数据量。不过,我不认为有任何异步事件通知,这将使您不得不轮询。
发布于 2011-10-18 12:51:55
我知道这是一条老生常谈,但是为了那些通过搜索引擎偶然发现这个问题的人的利益,我会回答这个问题,因为上面并没有真正的答案。
在我开始之前,克服系统调用挂起-您不能与基于内核的(*nix)网络堆栈交互,而不切换到内核空间。你的目标应该是理解堆栈特性,这样你就能从你的系统中得到最好的结果。
如何判断读套接字缓冲区是否已满
这部分已经被回答了-你没有,因为这不是你应该怎么想。
如果发送方(严重的)分割了它的TCP帧(通常是因为没有缓冲输出的封送数据,并且使用TCP_NDELAY关闭了Nagle算法),那么减少系统调用的数量是个好主意。您应该使用的方法包括设置一个“低水印”进行读取。首先,通过使用setsockopt()设置SO_RCVBUF来确定您认为合理的接收缓冲区大小。然后使用getsockopt()返回实际的读取缓冲区大小,因为您可能没有得到所要求的内容。)不幸的是,并不是所有的实现都允许您再次读取SO_RCVBUF,因此您的里程可能会有所不同。接下来,在您想要阅读之前,确定要显示多少数据供阅读。使用setsockopt()设置具有此大小的SO_RCVLOWAT。现在,套接字的文件描述符只有在读取的数据量至少有那么多时才会选择可读性。
还是写套接字缓冲区是空的?
这是一个有趣的问题,因为我最近需要这样做,以确保MODBUS/TCP各自占用自己的TCP帧,而MODBUS规范要求这样做(@steve:控制碎片是一次您需要知道何时发送缓冲区为空!)。就原来的海报而言,我非常怀疑他是否真的想这样做,并相信他在开始之前知道发送缓冲区的大小,并在发送过程中定期检查发送缓冲区中的数据量,使用已经描述的技术,会得到更好的服务。这将提供关于所使用的发送缓冲区比例的更细粒度的信息,可以用来更平稳地控制生产。
对于那些仍然感兴趣的人,当发送缓冲区为空(一旦您确定它确实是您想要的)时,仍然感兴趣的是如何检测(异步),答案很简单-您设置发送低水印(SO_SNDLOWAT)等于发送缓冲区大小。这样,当发送缓冲区为空时,套接字的文件描述符才会选择为可写。
我对你的问题的回答是围绕着select()的使用而进行的,这不是巧合。在几乎所有的情况下(我意识到我现在正在进入宗教领域!)需要移动大量数据的应用程序(主机内部和主机间)的结构最好是单线程状态机,使用选择掩码和基于pselect()的处理循环。这些天来,一些OS (Linux )甚至允许您使用文件描述符选择来管理您的信号处理。多奢侈-当我还是个孩子的时候.:)
彼得
https://stackoverflow.com/questions/1803215
复制相似问题