私はC++でRTSPソースフィルターを開発しており、WINSOCK2.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アドレスへのソケットを作成し、それを接続しようとすると、SOCKET_ERRORを返す前に約10秒間ハングします。したがって、IPがネットワーク上に存在しない場合、_SO_RCVTIMEO
_は無視されます...
質問:2番目のケースでは、存在しないIPのタイムアウトを設定するにはどうすればよいですか? IPが存在するかどうかを確認するために最初にICMPPINGを送信する必要がありますか、それともそのような他のチェックを実行する必要がありますか?
どんな助けでもありがたいです。ありがとう。 :)
私の問題への答え
ブロッキングソケットを使用しているため、接続が確立されるまで、またはホストが応答しないために接続が失敗するか、接続を拒否するまで、connect()
ブロックを呼び出します。ソケットのタイムアウトを3秒に設定し、存在しないホストに接続しようとすると、PC(クライアント)はSYN
フラグが設定されたTCPパケットを送信して、スリーウェイハンドシェイク。通常、ホストは、起動している場合、ACK
およびSYN
フラグが設定されたTCPパケットで応答し、クライアント(me)はACK
フラグが設定されたTCPパケットを送信します。次に、接続が確立されます。ただし、ホストがダウンしていてSYN
が送信された場合、クライアントは3秒のタイムアウトが経過するまで待機してから、TcpMaxConnectRetransmissions
( Microsoft ARTICLE )レジストリ設定に達するまでAGAINとAGAINを試行します。ホストは稼働している可能性がありますが、SYN
パケットが失われる可能性があります...私のWindowsXPはこの設定が4になっていると思います。したがって、SYN
を送信しようとするたびに、3秒間待機し、 4回目の試行は失敗し、_SOCKET_ERROR
_(12秒後)を返し、最後のWSAエラーとしてWSAETIMEDOUT
を設定します。
これを回避する方法は、非ブロッキングソケットを使用し、Martin Jamesが提案したように、接続試行時間を手動で測定しようとすることです(現在、connect()
はブロックされないため)。
別の方法は、最後の手段であるレジストリをいじることです...
弾丸をかみます。リモートIPがPINGサーバーを実行していないか、PINGが一部のルーターによってブロックされている可能性があるため、役に立ちません。 10秒間待ってから、使用するエラー表示を行うことはできませんか?
試行された接続を3秒後に絶対にタイムアウトする必要がある場合は、自分でタイムアウトすることができます。
実際、バークレーソケットには接続のタイムアウトがないため、設定できません。 ICMP PINGは役に立ちません。理由はわかりませんが、ホストが存在しない場合は、PINGで約1秒を費やします。ホストが存在することを検出するためにARPを使用してみてください。
cmdから、次のようなタイムアウトでIPにpingを実行できます 'ping -w 100 -n 1 192.168.1.1'
100mS以内に戻ります
'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;
}