【发布时间】: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,则一切正常,但是:
-
如果我的过滤器创建一个到现有 IP 地址的套接字,但在没有人监听的随机端口上,
connect()等待 3 秒并返回WSAETIMEDOUT。所以 3 秒后,我知道提供的 URL 是错误的。 -
如果我的过滤器创建一个到不存在的 IP 地址的套接字并尝试连接它,它会挂起大约 10 秒,然后返回 SOCKET_ERROR。因此,如果网络上不存在 IP,
SO_RCVTIMEO将被忽略...
问题: 在第二种情况下,如何为不存在的 IP 设置超时?我是否需要先发送 ICMP PING 以查看 IP 是否存在,或者执行其他类似的检查?
任何帮助将不胜感激。 谢谢。 :)
我的问题的答案
因为我使用阻塞套接字,所以调用connect()阻塞,直到连接建立,或者连接失败,因为主机没有响应,或者它拒绝连接。如果我将套接字的超时设置为 3 秒,并尝试连接到不存在的主机,我的电脑(客户端)将发送带有 SYN 标志的 TCP 数据包,以启动 三路握手。通常,如果主机启动,将响应包含ACK 和SYN 标志设置的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() ;)