【问题标题】:WINSOCK - Setting a timeout for a connection attempt on a non existing IP?WINSOCK - 为不存在的 IP 上的连接尝试设置超时?
【发布时间】:2011-06-01 09:37:13
【问题描述】:

我正在用 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 秒并返回 WSAETIMEDOUT。所以 3 秒后,我知道提供的 URL 是错误的。

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

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

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

我的问题的答案

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

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

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

【问题讨论】:

  • 这是在 Windows 还是控制台应用程序中?这个问题很重要,因为它让我知道您可以使用 wsapi 中的哪些工具。
  • DirectShow Push Source过滤器,DLL库。
  • 我忘记了,DLLMain 传递了一个 hwnd?如果没有,best 选项是创建一个仅 hwnd 的窗口(所以你得到的唯一东西是消息泵和 WndProc,将套接字设置为非阻塞,WSAAsync,创建一个关闭的计时器套接字(它是一个无符号整数,确切地说是创建计时器所需要的),当你的计时器消息到达你的消息循环时,你知道它已经超时了。(这就是我在制作 socks 5 检查器时所做的,它获取了 socks5 代理列表和检查有效性。
  • 我没有 WndProc,但是非阻塞套接字的想法很好。 ;)
  • 好吧,要获得一个wind proc(相信我你想要它),你必须创建一个只是一个 HWND 的窗口,即它没有可视用户界面,它为你提供了一个消息循环不过,你可以用它告诉套接字是 WSAAsyncSelect() ;)

标签: c++ winsock2


【解决方案1】:

咬紧牙关。远程 IP 可能没有运行 PING 服务器,或者 PING 可能被某些路由器阻止,因此无济于事。你能不能只等待 10 秒,然后做出你使用的任何错误指示?

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

【讨论】:

  • 我得到了 ping 捕获,但我自己怎么能超时呢?如何在套接字仍在尝试连接时停止来自另一个线程的连接尝试?我需要connect() 函数返回,这样我才能有一个工作的可断开套接字。还是我错了?
【解决方案2】:

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

【讨论】:

  • 实际上,ARP 不是一个选项,因为服务器在 WAN 上,而不是在 LAN 上,所以 ARP 不起作用......还是我错了?
  • Wiki 表示 ARP 存在于 IEEE 802.11
  • 好吧,就像我说的......在局域网上我可以通过UDP广播ARP请求WHO HAS 192.168.0.22,并且与192.168.0.22的接口响应I DO, THIS IS MY MAC 00:11:22:33:44:55。但听起来不可能世界上所有的 PC 都会在 WAN 上收到我的 ARP 请求,然后只有其中一台会响应。 ARP 请求永远不会超出本地网络。所以,我试过了,它只能在局域网上运行......正如预期的那样。 :)
  • 所以只有一种方式,比如 Martin James
【解决方案3】:

您可以从 cmd ping ip 超时,例如 'ping -w 100 -n 1 192.168.1.1'

它将在 100 毫秒内返回

你可以通过'echo %errorlevel% 0 = ok, 1 = fail来检查返回码,然后你知道你是否应该尝试连接

在 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;
} 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-21
    • 1970-01-01
    • 2015-01-03
    • 1970-01-01
    • 1970-01-01
    • 2018-01-18
    • 1970-01-01
    • 2021-05-15
    相关资源
    最近更新 更多