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

发布于 2025-01-02 19:10:03 字数 356 浏览 2 评论 0原文

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

为了控制套接字之间的正确流量,如果目标套接字上的写入可能会阻塞,则应用程序不应从源套接字读取数据。 这个想法很好,但是我发现没有办法在不先写入目标套接字的情况下检测目标套接字的阻塞状态......而这不是所需要的。

我知道有一个选项可以使用 SIOCOUTQ (使用 ioctl())并计算剩余缓冲区,但这与简单检查目标套接字是否准备好相比似乎很难看写作。

我想我也可以对这个套接字使用 select() ,但这对如此繁重的系统调用来说太浪费了。

I'm currently writing a proxy application that reads from one socket and writes on another. Both are set as non-blocking, allowing multiple sockets pairs to be handle.

To control a proper flow between the sockets, the application should NOT read from the source socket if the writing on the target socket may block.
The idea is nice, however I found no way to detect a blocking state of the target socket without first writing to it... and that is not what is needed.

I know of an option to use SIOCOUTQ (using ioctl()) and calculate the remaining buffer, but this seems ugly compared to a simple check if the target socket is ready for writing.

I guess I can also use select() for just this socket, but that is so much waste of a such heavy system call.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

宫墨修音 2025-01-09 19:10:03

selectpoll 应该能够为您提供信息。
我假设您已经在使用其中之一来检测哪个读取套接字有数据
当你有一个读套接字可供读取时,将其替换为相应的写套接字(当然将其放在写文件描述符中),然后再次调用select。然后,如果写入套接字可用,则可以读取和写入。

请注意,写入套接字可能已准备好获取数据,但没有达到您想要的程度。因此您可能会设法读取 100 个字节,但只写入 50 个字节。

select or poll should be able to give you the information.
I assume you're already using one of them to detect which of your reading sockets has data
When you have a reading socket available for read, replace it with the corresponding writing socket (but put it in the write fds of course), and call select again. Then, if the writing socket is available, you can read and write.

Note that it's possible that the writing socket is ready to get data, but not as much as you want. So you might manage to read 100 bytes, and write only 50.

洒一地阳光 2025-01-09 19:10:03

感谢大家的反馈。

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

直接回答问题,检测套接字在尝试写入时会阻塞的唯一已知方法是使用 select/poll/epoll

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

  1. 使用SIOCOUTQ来查明目标套接字上还剩下多少缓冲区,并且传输的内容不会超过该值。正如@ugoren所指出的,这有一个不可靠的缺点,主要是因为在读取值、计算值和尝试写入实际值之间可能会发生变化。如果管理不当,还会带来一些忙等待的问题。我想,如果要使用这项技术,那么应该采用一种更可靠的技术来进行全面保护。

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

再次感谢大家参与这次讨论,这对我理清思路很有帮助。

Thank you all for the feedback.

Summarizing all comments and answers up until now:

Directly to the question, the only known way to detect that a socket will block on an attempt to write to it is using select/poll/epoll.

The original objective was to build a proxy, which reads from one socket and writes to another, keeping proper balance between them (reading at the same rate of writing and vice versa) and using no major buffering in the application. For this, the following options were presented:

  1. Use of SIOCOUTQ to find out how much buffer is left on the destination socket and transmit no more than that. As pointed out by @ugoren, this has a disadvantage of being unreliable, mainly because in between reading the value, calculating it and attempting to write the actual value may change. It also introduces some issues of busy-waiting if wrongly managed. I guess, if this technique is to be used, it should be followed by a more reliable one for full protection.

  2. Use of select/poll/epoll and adding a small limited buffer per read socket: Initially, all read sockets will be added to the poll, when ready for read, we read it in a limited buffer size, then remove the read socket from the poll and add instead of it the destination socket for writing, when we return to the poll and we detect that the destination socket is ready for writing, we write the buffer, if all data was accepted by the socket, we remove the destination socket from the poll and return the read socket back. The disadvantage here is that we increase the number of system calls (adding/removing to the poll/select) and we need to keep an internal buffer per socket. This seems to be the preferred approach, and some optimization could be added to try and reduce the call to system calls (for example, trying to write right after reading the read socket, and only if something is left to perform the above).

Thank you all again for participating in this discussion, it helped me a lot ordering the ideas.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文