Linux 建立多个连接时如何在C中设置套接字超时?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4181784/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to set socket timeout in C when making multiple connections?
提问by RichardLiu
I'm writing a simple program that makes multiple connections to different servers for status check. All these connections are constructed on-demand; up to 10 connections can be created simultaneously. I don't like the idea of one-thread-per-socket, so I made all these client sockets Non-Blocking, and throw them into a select() pool.
我正在编写一个简单的程序,它与不同的服务器建立多个连接以进行状态检查。所有这些连接都是按需构建的;最多可以同时创建 10 个连接。我不喜欢每个套接字一个线程的想法,因此我将所有这些客户端套接字设为非阻塞,并将它们放入 select() 池中。
It worked great, until my client complained that the waiting time is too long before they can get the error report when target servers stopped responding.
它工作得很好,直到我的客户抱怨等待时间太长才能在目标服务器停止响应时获得错误报告。
I've checked several topics in the forum. Some had suggested that one can use alarm() signal or set a timeout in the select() function call. But I'm dealing with multiple connections, instead of one. When a process wide timeout signal happens, I've no way to distinguish the timeout connection among all the other connections.
我检查了论坛中的几个主题。有人建议可以使用 alarm() 信号或在 select() 函数调用中设置超时。但我正在处理多个连接,而不是一个。当进程范围的超时信号发生时,我无法在所有其他连接中区分超时连接。
Is there anyway to change the system-default timeout duration ?
无论如何要更改系统默认超时持续时间?
采纳答案by Toby
You can use the SO_RCVTIMEO and SO_SNDTIMEO socket options to set timeouts for any socket operations, like so:
您可以使用 SO_RCVTIMEO 和 SO_SNDTIMEO 套接字选项为任何套接字操作设置超时,如下所示:
struct timeval timeout;
timeout.tv_sec = 10;
timeout.tv_usec = 0;
if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
sizeof(timeout)) < 0)
error("setsockopt failed\n");
if (setsockopt (sockfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,
sizeof(timeout)) < 0)
error("setsockopt failed\n");
Edit:from the setsockopt
man page:
编辑:从setsockopt
手册页:
SO_SNDTIMEO
is an option to set a timeout value for output operations. It accepts a struct timeval parameter with the number of seconds and microseconds used to limit waits for output operations to complete. If a send operation has blocked for this much time, it returns with a partial count or with the error EWOULDBLOCK if no data were sent. In the current implementation, this timer is restarted each time additional data are delivered to the protocol, implying that the limit applies to output portions ranging in size from the low-water mark to the high-water mark for output.
SO_SNDTIMEO
是为输出操作设置超时值的选项。它接受一个 struct timeval 参数,其中包含用于限制等待输出操作完成的秒数和微秒数。如果发送操作阻塞了这么长时间,它会返回一个部分计数或错误 EWOULDBLOCK 如果没有发送数据。在当前的实现中,每次额外的数据被传送到协议时,这个定时器都会重新启动,这意味着限制适用于大小从低水位线到高水位线的输出部分。
SO_RCVTIMEO
is an option to set a timeout value for input operations. It accepts a struct timeval parameter with the number of seconds and microseconds used to limit waits for input operations to complete. In the current implementation, this timer is restarted each time additional data are received by the protocol, and thus the limit is in effect an inactivity timer. If a receive operation has been blocked for this much time without receiving additional data, it returns with a short count or with the error EWOULDBLOCK if no data were received. The struct timeval parameter must represent a positive time interval; otherwise, setsockopt() returns with the error EDOM.
SO_RCVTIMEO
是为输入操作设置超时值的选项。它接受一个 struct timeval 参数,其中包含用于限制等待输入操作完成的秒数和微秒数。在当前的实现中,每当协议接收到额外的数据时,这个定时器就会重新启动,因此限制实际上是一个不活动的定时器。如果接收操作被阻塞了这么长时间而没有接收到额外的数据,它会返回一个简短的计数,或者如果没有接收到数据,则返回错误 EWOULDBLOCK。struct timeval 参数必须表示正时间间隔;否则,setsockopt() 返回错误 EDOM。
回答by Zan Lynx
Can't you implement your own timeout system?
你不能实现自己的超时系统吗?
Keep a sorted list, or better yet a priority heap as Heath suggests, of timeout events. In your select or poll calls use the timeout value from the top of the timeout list. When that timeout arrives, do that action attached to that timeout.
保留一个排序的列表,或者更好的是 Heath 建议的优先级堆,超时事件。在您的选择或轮询调用中,使用超时列表顶部的超时值。当该超时到达时,执行附加到该超时的操作。
That action could be closing a socket that hasn't connected yet.
该操作可能是关闭尚未连接的套接字。
回答by wgr
am not sure if I fully understand the issue, but guess it's related to the one I had, am using Qt with TCP socket communication, all non-blocking, both Windows and Linux..
我不确定我是否完全理解这个问题,但我猜它与我的问题有关,正在使用 Qt 和 TCP 套接字通信,所有非阻塞,Windows 和 Linux..
wanted to get a quick notification when an already connected client failed or completely disappeared, and not waiting the default 900+ seconds until the disconnect signal got raised. The trick to get this working was to set the TCP_USER_TIMEOUT socket option of the SOL_TCP layer to the required value, given in milliseconds.
想要在已经连接的客户端失败或完全消失时获得快速通知,而不是等待默认的 900 秒以上,直到断开信号出现。使其工作的技巧是将 SOL_TCP 层的 TCP_USER_TIMEOUT 套接字选项设置为所需的值,以毫秒为单位。
this is a comparably new option, pls see http://tools.ietf.org/html/rfc5482, but apparently it's working fine, tried it with WinXP, Win7/x64 and Kubuntu 12.04/x64, my choice of 10 s turned out to be a bit longer, but much better than anything else I've tried before ;-)
这是一个相对较新的选项,请参阅http://tools.ietf.org/html/rfc5482,但显然它工作正常,在 WinXP、Win7/x64 和 Kubuntu 12.04/x64 上尝试过,结果我选择了 10 秒更长一点,但比我以前尝试过的其他任何东西都要好;-)
the only issue I came across was to find the proper includes, as apparently this isn't added to the standard socket includes (yet..), so finally I defined them myself as follows:
我遇到的唯一问题是找到正确的包含,因为显然这没有添加到标准套接字包含中(还......),所以最后我自己定义如下:
#ifdef WIN32
#include <winsock2.h>
#else
#include <sys/socket.h>
#endif
#ifndef SOL_TCP
#define SOL_TCP 6 // socket options TCP level
#endif
#ifndef TCP_USER_TIMEOUT
#define TCP_USER_TIMEOUT 18 // how long for loss retry before timeout [ms]
#endif
setting this socket option only works when the client is already connected, the lines of code look like:
设置此套接字选项仅在客户端已连接时有效,代码行如下所示:
int timeout = 10000; // user timeout in milliseconds [ms]
setsockopt (fd, SOL_TCP, TCP_USER_TIMEOUT, (char*) &timeout, sizeof (timeout));
and the failure of an initial connect is caught by a timer started when calling connect(), as there will be no signal of Qt for this, the connect signal will no be raised, as there will be no connection, and the disconnect signal will also not be raised, as there hasn't been a connection yet..
并且初始连接的失败被调用 connect() 时启动的计时器捕获,因为不会有 Qt 的信号,因此不会引发连接信号,因为将没有连接,并且断开信号将也没有被提出,因为还没有建立联系..
回答by Couannette
connect
timeout has to be handled with a non-blocking socket (GNU LibC documentationon connect
). You get connect
to return immediately and then use select
to wait with a timeout for the connection to complete.
connect
超时必须与非阻塞插座(GNU的LibC处理文档上connect
)。您可以connect
立即返回,然后使用select
超时等待连接完成。
This is also explained here : Operation now in progress error on connect( function) error.
这也在这里解释:操作现在进行中错误连接(函数)错误。
int wait_on_sock(int sock, long timeout, int r, int w)
{
struct timeval tv = {0,0};
fd_set fdset;
fd_set *rfds, *wfds;
int n, so_error;
unsigned so_len;
FD_ZERO (&fdset);
FD_SET (sock, &fdset);
tv.tv_sec = timeout;
tv.tv_usec = 0;
TRACES ("wait in progress tv={%ld,%ld} ...\n",
tv.tv_sec, tv.tv_usec);
if (r) rfds = &fdset; else rfds = NULL;
if (w) wfds = &fdset; else wfds = NULL;
TEMP_FAILURE_RETRY (n = select (sock+1, rfds, wfds, NULL, &tv));
switch (n) {
case 0:
ERROR ("wait timed out\n");
return -errno;
case -1:
ERROR_SYS ("error during wait\n");
return -errno;
default:
// select tell us that sock is ready, test it
so_len = sizeof(so_error);
so_error = 0;
getsockopt (sock, SOL_SOCKET, SO_ERROR, &so_error, &so_len);
if (so_error == 0)
return 0;
errno = so_error;
ERROR_SYS ("wait failed\n");
return -errno;
}
}