代理需要非阻塞套接字吗?
我有以下代码:
{
send(dstSocket, rcvBuffer, recvMsgSize, 0);
sndMsgSize = recv(dstSocket, sndBuffer, RCVBUFSIZE, 0);
send(rcvSocket, sndBuffer, sndMsgSize, 0);
recvMsgSize = recv(rcvSocket, rcvBuffer, RCVBUFSIZE, 0);
}
它最终应该成为通用 TCP 代理的一部分。现在,它不能正常工作,因为 recv() 等待输入,因此数据只能以块的形式传输,具体取决于它当前所在的位置。
我读到的内容是,我需要诸如“非阻塞套接字”之类的东西和一种监视它们的机制。我发现这种机制在 Linux 中要么是 select、poll 要么是 epoll。谁能给我确认我走在正确的轨道上吗?或者这个练习也可以通过阻塞套接字来完成吗?
问候
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
你走在正确的轨道上。
“select”和“poll”是系统调用,您可以在其中传递一个或多个套接字并阻塞(一段特定的时间),直到在这些套接字之一上接收到(或准备发送)数据。
“非阻塞套接字”是一个可以应用于套接字(或recv调用标志)的设置,这样如果您尝试调用recv,但没有可用数据,则调用将立即返回。 “发送”也存在类似的语义。您可以使用带或不带上述 select/poll 方法的非阻塞套接字。使用非阻塞操作通常不是一个坏主意,以防万一您收到不存在数据的信号。
“epoll”是 select 和 poll 的高度可扩展版本。 “选择”集实际上仅限于一次监视 64-256 个套接字,并且随着监视的套接字数量的增加,性能会受到影响。 “epoll”可以扩展到数千个同时网络连接。
You are on the right track.
"select" and "poll" are system calls where you can pass in one or more sockets and block (for a specific amount of time) until data has been received (or ready for sending) on one of those sockets.
"non-blocking sockets" is a setting you can apply to a socket (or a recv call flag) such that if you try to call recv, but no data is available, the call will return immediately. Similar semantics exist for "send". You can use non-blocking sockets with or without the select/poll method described above. It's usually not a bad idea to use non-blocking operations just in case you get signaled for data that isn't there.
"epoll" is a highly scalable version of select and poll. A "select" set is actually limited to something like 64-256 sockets for monitoring at a time and it takes a perf hit as the number of monitored sockets goes up. "epoll" can scale up to thousands of simultaneous network connections.
是的,你走在正确的轨道上。使用非阻塞套接字传递其相对文件描述符进行选择(请参阅 FD_SET())。
这种方式选择将监视它们上的事件(读/写)。
当 select 返回时,您可以检查哪个 fd 发生了事件(查看 FD_ISSET())并处理它。
您还可以在 select 上设置超时,即使没有发生事件,它也会在该时间段后返回。
Yes you are in the right track. Use non-blocking socket passing their relative file descriptors to select (see FD_SET()).
This way select will monitor for events (read/write) on them.
When select returns you can check on which fd has occurred an event (look at FD_ISSET()) and handle it.
You can also set a timeout on select, and it will return after that period even if not events have been occurred.
是的,您必须使用其中一种机制。 poll 是便携式的,在我看来是最容易使用的。在这种情况下,您不必关闭阻塞,只要您为
RCVBUFSIZE
使用足够小的值(大约 2k-10k 应该是合适的)。非阻塞套接字处理起来有点复杂,因为如果你在发送时收到EAGAIN
,你不能只是循环重试(当然可以,但你不应该这样做,因为它使用 CPU不必要)。但我建议使用 libevent 等包装器。在这种情况下,struct bufferevent 会工作得特别好。当有新数据可用时,它会进行回调,您只需将其排队以便在另一个套接字上发送即可。
试图找到一个 bufferevent 示例,但似乎有点缺乏。无论如何,文档在这里: http://monkey.org/~provos /libevent/doxygen-2.0.1/index.html
Yes you'll have to use one of those mechanisms. poll is portable and IMO the most easy one to use. You don't have to turn off blocking in this case, provided you use a small enough value for
RCVBUFSIZE
(around 2k-10k should be appropriate). Non-blocking sockets are a bit more complicated to handle, since if you getEAGAIN
on send, you can't just loop to try again (well you can, but you shouldn't since it uses CPU unnecessarily).But I would recommend to use a wrapper such as libevent. In this case a
struct bufferevent
would work particularly well. It will make a callback when new data is available, and you just queue it up for sending on the other socket.Tried to find an bufferevent example but seems to be a bit short on them. The documentation is here anyway: http://monkey.org/~provos/libevent/doxygen-2.0.1/index.html