2011-06-01 149 views
16

我正在开发C++中的RTSP源代码过滤器,并且使用WINSOCK 2.0 - 阻塞套接字。WINSOCK - 在不存在的IP上设置连接尝试超时?

当我创建一个阻塞套接字,我设置其SO_RCVTIMEO至3秒,像这样:

int ReceiveTimeout = 3000; 
int e = setsockopt(Socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&ReceiveTimeout, sizeof(int)); 

我的过滤器试图连接到IP_ADDRESS:554(554 RTSP服务器端口)。如果有一个服务器侦听的端口554上IP,一切顺利,但是:

  1. 如果我的过滤器创建一个套接字到现有IP地址,但一个随机端口上没人听connect()等待3秒钟并返回WSAETIMEDOUT。所以3秒后,我知道提供的URL是不好的。

  2. 如果我的过滤器创建一个套接字到不存在的IP地址,并尝试连接,它返回SOCKET_ERROR前挂机约10秒。因此,如果IP不存在网络上SO_RCVTIMEO被忽略......

问题: 如何设置超时为不存在的IP,在第二种情况下?我是否需要首先发送ICMP PING来查看IP是否存在,或者执行其他类似的检查?

任何帮助将不胜感激。 Thanx。 :)

我的问题的答案

因为我使用的是阻塞插座,来电connect()块,直到建立连接,或者因为主机没有响应连接失败,或者被拒绝连接。如果我将套接字的超时设置为3秒,并尝试连接到一个不存在的主机,我的电脑(客户端)将发送带有SYN标志的TCP数据包,启动三通握手。通常情况下,主机如果启用,将使用包含ACKSYN标志集的TCP数据包进行响应,然后客户机(我)将发送标记为ACK的TCP数据包。然后建立连接。但是如果主机关闭,并且发送了SYN,则客户端会等到3秒超时过期,然后再次尝试重新尝试,直到达到TcpMaxConnectRetransmissionsMICROSOFT ARTICLE)注册表设置为止,因为主机可以处于UP状态,但是SYN数据包可能会丢失...我的Windows XP的设置为4,我猜,所以每次尝试发送SYN时,它会等待3秒,当第四次尝试失败时,它会返回SOCKET_ERROR(12秒后),并且将WSAETIMEDOUT设置为最后一次WSA错误。

解决方法是使用非阻塞套接字,并尝试手动测量连接尝试时间(因为现在connect()不会像Martin James所建议的那样)。

另一种方法是使用注册表,这是不得已而为之拨弄......

+0

这是在Windows或控制台应用程序?这个问题很重要,因为它让我知道你可以使用的wsapi中的哪些工具。 – johnathon 2011-06-01 12:23:47

+0

它是一个DirectShow推送源过滤器,DLL库。 – Cipi 2011-06-01 12:29:28

回答

2

勉为其难。远程IP可能没有运行PING服务器,或者PING可能被某个路由器阻塞,所以没有任何帮助。你能不能等待10秒,然后做出你使用的任何错误指示?

如果您绝对必须在3秒后超时尝试连接,您可以自行计时。

+2

我得到了ping,但我怎么能自己计算出来呢?当它仍在尝试连接时,如何阻止来自另一个线程的套接字连接尝试?我需要'connect()'函数来返回,以便我可以有一个可拆卸的插座。或者我错了? – Cipi 2011-06-01 10:18:07

2

事实上,伯克利套接字没有超时连接,所以你不能设置它。 ICMP PING没有什么帮助,我不知道为什么,但是如果主机不存在,你会花1秒左右的时间与PING联系。尝试使用ARP来检测是否存在主机。

+0

其实,ARP并不是一种选择,因为服务器在广域网上,而不是在局域网上,所以ARP不会工作......或者我错了? – Cipi 2011-06-01 10:48:25

+0

[Wiki](http://en.wikipedia.org/wiki/Address_Resolution_Protocol)表示ARP存在于IEEE 802.11 – xandox 2011-06-01 11:26:30

+0

Ooook会尝试它。 – Cipi 2011-06-01 11:39:32

0
从CMD可以ping IP,像这样“平-w 100-N 1 192.168.1.1”

它将在100ms内

返回您可以通过“回声检查返回码超时

%ERRORLEVEL%0 =正常,1 =失败,那么你知道你应该尝试在C++连接

bool pingip_nowait(const char* ipaddr) 
{ 
    DWORD exitCode; 

    STARTUPINFO si; 
    PROCESS_INFORMATION pi; 

    ZeroMemory(&si, sizeof(si)); 
    si.cb = sizeof(si); 
    ZeroMemory(&pi, sizeof(pi)); 
    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; 
    si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); 
    si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); 
    si.hStdError = GetStdHandle(STD_ERROR_HANDLE); 
    si.wShowWindow = SW_HIDE; 

    CString cmd = "ping -w 100 -n 1 "; 
    cmd += ipaddr; 
    if (!CreateProcess(NULL, 
     cmd.GetBuffer(), 
     NULL, 
     NULL, 
     FALSE, 
     0, 
     NULL, 
     NULL, 
     &si, 
     &pi)) { 
      TRACE("ERROR: Cannot launch child process\n"); 
      return false; 
    } 

    // Give the process time to execute and finish 
    WaitForSingleObject(pi.hProcess, 200L); 

    if (GetExitCodeProcess(pi.hProcess, &exitCode)) 
    { 
     TRACE("ping returned %d\n", exitCode); 
     // Close process and thread handles. 
     CloseHandle(pi.hProcess); 
     CloseHandle(pi.hThread); 
     return exitCode==0 ? true : false; 
    } 
    TRACE("GetExitCodeProcess() failed\n"); 
    CloseHandle(pi.hProcess); 
    CloseHandle(pi.hThread); 
    return false; 
}