我目前正在编写一个代理应用程序,它从一个套接字读取并在另一个套接字上写入。两者都设置为非阻塞,允许处理多个套接字对。
要控制套接字之间的正常流,如果目标套接字上的写入可能会阻塞,则应用程序不应从源套接字读取。 这个想法很好,但是我发现如果没有先写入目标套接字就无法检测到目标套接字的阻塞状态......这不是我们所需要的。
我知道使用SIOCOUTQ
(使用ioctl()
)并计算剩余缓冲区的选项,但与简单检查相比,如果目标套接字已准备好写入,这似乎很难看。
我想我也可以使用select()
作为这个套接字,但这太浪费了这么重的系统调用。
答案 0 :(得分:1)
select
或poll
应该能够为您提供相关信息
我假设您已经使用其中一个来检测哪些读取插座有数据
如果您有一个可供读取的读取套接字,请将其替换为相应的写入套接字(当然,将其置于写入fds中),然后再次调用select
。然后,如果写入套接字可用,您可以读写。
请注意,写入套接字可能已准备好获取数据,但可能没有您想要的数据。所以你可能设法读取100个字节,只写50。
答案 1 :(得分:1)
谢谢大家的反馈。
到目前为止总结所有评论和答案:
直接针对这个问题,检测套接字会阻止尝试写入套接字的唯一已知方法是使用select
/ poll
/ epoll
。
最初的目标是构建一个代理,它从一个套接字读取并写入另一个套接字,在它们之间保持适当的平衡(以相同的写入速率读取,反之亦然)并且在应用程序中不使用主要缓冲。为此,提出了以下选项:
使用SIOCOUTQ
查找目标套接字上剩余的缓冲区数量,并传输不超过该数量。正如 @ugoren 所指出的,这有一个不可靠的缺点,主要是因为在读取值之间,计算它并尝试写入实际值可能会改变。如果管理错误,它还会引入一些繁忙等待的问题。我想,如果要使用这种技术,应该使用更可靠的技术进行全面保护。
使用select
/ poll
/ epoll
并为每个读取套接字添加一个小的有限缓冲区:最初,所有读取套接字都将添加到poll
,当我们准备好读取时,我们以有限的缓冲区大小读取它,然后从poll
中删除读取套接字,并在我们返回poll
时添加而不是用于写入的目标套接字检测到目标套接字已准备好写入,我们编写缓冲区,如果套接字接受了所有数据,我们从轮询中删除目标套接字并返回读取套接字。这里的缺点是我们增加了系统调用的数量(添加/删除poll
/ select
),我们需要为每个插槽保留一个内部缓冲区。这似乎是首选方法,可以添加一些优化来尝试减少对系统调用的调用(例如,尝试在读取读取套接字后立即写入,并且只有在执行上述操作时才会执行上述操作)。 / p>
再次感谢大家参与这次讨论,它帮助我订了很多想法。