我正在寻找一种有效的C / C ++方法来检查服务器是否可以在特定端口上访问。基本上,我们的想法是通过socket
在客户端上打开套接字,并通过connect
连接到此端口上的服务器。
在完全无法访问的服务器上使用阻塞套接字时,我必须等到达到默认超时。如果服务器正在运行,但端口未公开connect
,则会立即返回SOCKET_ERROR
。
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
int rc = connect(s, (SOCKADDR*)&target, sizeof(target));
closesocket(s);
if (rc == SOCKET_ERROR)
return false;
else
return true
在根本无法访问的服务器上使用非阻塞套接字时,我的行为与端口未公开的情况相同。我总是要等待定义的超时(在下面的例子中为10秒)。
// open socket
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// set mode to unblocking
unsigned long mode = 1;
int rc = ioctlsocket(s, FIONBIO, &mode);
rc = connect(s, (SOCKADDR*)&target, sizeof(target));
struct timeval tv;
tv.tv_sec = 10;
tv.tv_usec = 0;
fd_set read;
FD_ZERO(&read);
FD_SET(s, &read);
fd_set write = read;
rc = select(NULL, &read, NULL, NULL, &tv);
closesocket(s);
if (rc == 0 || rc == SOCKET_ERROR)
return false;
else
return true;
所以问题是,是否有办法结合两种方法的优点。这意味着如果服务器正常工作,立即获得结果,但不暴露端口,如果服务器不工作,则在指定的超时后获取此信息。
我尝试使用带有选项SO_RCVTIMEO
和SO_SNDTIMEO
的阻止套接字。这也不起作用,因为我喜欢并行探测不同的服务器/端口,非阻塞方法对我来说更方便。
答案 0 :(得分:1)
如果服务器可以访问,但端口不可访问,则非阻塞套接字会立即失败,而不是等待完全超时。但是你没有检测到这一点,因为你使用的是select()
错误的方式。
您正在等待readfds
参数。如果非阻塞套接字无法连接,select()
将不报告套接字是否可读。如果套接字成功连接,则在服务器向客户端发送字节之前,套接字不会被报告为可读。
要正确检测非阻止connect()
的结果,您需要使用writefds
的{{1}}和exceptfds
参数。这在select()
documentation on MSDN:
总之,当select返回时,将在特定集中标识套接字:
readfds:
- 如果已调用listen且连接处于挂起状态,则accept将成功。
- 可以读取数据(如果启用了SO_OOBINLINE,则包括OOB数据)。
- 连接已关闭/重置/终止。
writefds:
- 如果处理连接呼叫(非阻塞),则连接已成功。
- 可以发送数据。
exceptfds:
- 如果处理连接呼叫(非阻塞),则连接尝试失败。
- OOB数据可供阅读(仅当禁用SO_OOBINLINE时)。
如果非阻塞select()
失败,您必须使用connect()
和getsockopt()
操作码来获取实际的错误代码。
尝试更像这样的事情:
SO_ERROR