非阻塞TCP套接字处理 – 如何在写入套接字之前检测阻塞状态?

我正在编写一个代理应用程序,它从一个套接字读取并在另一个套接字上写入。 两者都设置为非阻塞,允许处理多个套接字对。

要控制套接字之间的正确流,如果目标套接字上的写入可能会阻塞,则应用程序不应从源套接字读取。 这个想法很好,但是我没有找到目标套接字的阻塞状态而没有先写入它就没有办法……而这并不是我们所需要的。

我知道使用SIOCOUTQ (使用ioctl() )并计算剩余缓冲区的选项,但与简单检查目标套接字是否准备好写入相比,这看起来很难看。

我想我也可以使用select()作为这个套接字,但这是一个如此繁重的系统调用的浪费。

selectpoll应该能够为您提供信息。
我假设您已经使用其中一个来检测哪些读取套接字有数据
如果您有一个可供读取的读取套接字,请将其替换为相应的写入套接字(当然,将其置于写入fds中),然后再次调用select 。 然后,如果写入套接字可用,您可以读写。

请注意,写入套接字可能已准备好获取数据,但可能没有您想要的那么多。 所以你可能设法读取100个字节,只写50个。

谢谢大家的反馈。

总结到目前为止的所有评论和答案:

直接问题是,检测套接字将阻止尝试写入的唯一已知方法是使用select / poll / epoll

最初的目标是构建一个代理,它从一个套接字读取并写入另一个套接字,在它们之间保持适当的平衡(以相同的写入速率读取,反之亦然)并且在应用程序中不使用主要缓冲。 为此,提出了以下选项:

  1. 使用SIOCOUTQ来确定目标套接字上剩余多少缓冲区并传输不超过这个缓冲区。 正如@ugoren指出的那样 ,这有一个不可靠的缺点,主要是因为在读取值之间,计算它和尝试写入实际值可能会改变。 如果管理错误,它还会引入一些繁忙等待的问题。 我想,如果要使用这种技术,应该使用更可靠的技术进行全面保护。

  2. 使用select / poll / epoll并为每个读取套接字添加一个小的有限缓冲区:最初,所有读取套接字都将添加到poll ,当准备好读取时,我们以有限的缓冲区大小读取它,然后从中删除读取套接字poll并添加而不是写入的目标套接字,当我们返回poll并且我们检测到目标套接字已准备好写入时,我们编写缓冲区,如果套接字接受了所有数据,我们将删除目标套接字轮询并返回读取套接字。 这里的缺点是我们增加了系统调用的数量(添加/删除poll / select ),我们需要为每个套接字保留一个内部缓冲区。 这似乎是首选方法,可以添加一些优化来尝试减少对系统调用的调用(例如,尝试在读取读取套接字后立即写入,并且只有在执行上述操作时才会执行此操作)。

再次感谢大家参与这次讨论,它帮我订了很多想法。