WINSOCK - 为非现有IP上的连接尝试设置超时?

时间:2011-06-01 09:37:14

标签: c++ winsock2

我正在用C ++开发一个RTSP源过滤器,我正在使用WINSOCK 2.0 - 阻塞套接字。

当我创建一个阻塞套接字时,我将其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秒并返回{{1 }}。所以在3秒后,我知道提供的网址很糟糕。

  2. 如果我的过滤器创建了一个非现有IP地址的套接字,并尝试连接它,它会在返回SOCKET_ERROR之前挂起约10秒。因此,如果网络上不存在IP,WSAETIMEDOUT将被忽略...

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

    任何帮助将不胜感激。 感谢名单。 :)

    回答我的问题

    因为我正在使用阻塞套接字,所以调用SO_RCVTIMEO块,直到建立连接,或者由于主机没有响应而导致连接失败,或者拒绝连接。如果我将套接字的超时设置为3秒,并尝试连接到不存在的主机,我的pc(客户端)将发送设置了connect()标志的TCP数据包,以启动 Threeway握手< / em>的。通常,主机(如果启动)将使用包含SYNACK标志的TCP数据包进行响应,然后,client(me)将发送设置了SYN标志的TCP数据包。然后建立连接。但是,如果主机已关闭,并且ACK已发送,则客户端会等待3秒超时,然后再尝试AGAIN和AGAIN,直到SYNMICROSOFT ARTICLE)注册表设置为止到达,因为主机可以UP但TcpMaxConnectRetransmissions数据包可能会丢失...我的Windows XP将此设置设置为4,我猜,所以每次尝试发送SYN时,它都会等待3秒,当第四次尝试失败时,它返回SYN(12秒后),并将SOCKET_ERROR设置为最后一次WSA错误。

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

    另一种方法是摆弄注册表,这是最后的手段......

3 个答案:

答案 0 :(得分:2)

咬紧牙关。远程IP可能没有运行PING服务器或PING可能被某些路由器阻止,所以没有帮助。你能不能等待10秒,然后做出你使用的任何错误指示?

如果你必须在3秒后完成尝试连接的时间,你可以自己计时。

答案 1 :(得分:2)

实际上,Berkeley套接字没有超时连接,所以你无法设置它。 ICMP PING没有帮助,我不知道为什么,但如果主机不存在,你花费大约1秒钟与PING。尝试使用ARP检测主机是否存在。

答案 2 :(得分:0)

从cmd你可以ping这个超时的ip'ping -w 100 -n 1 192.168.1.1'

它将在100mS内返回

你可以通过'echo%errorlevel%0 = ok,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;
}