web-dev-qa-db-ja.com

WINSOCK-存在しないIPでの接続試行のタイムアウトを設定しますか?

私は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をリッスンしているサーバーがある場合、すべてうまくいきますが、次のようになります。

  1. 私のフィルターが既存のIPアドレスへのソケットを作成するが、誰もリッスンしていないランダムなポートで、connect()が待機する場合3秒で、WSAETIMEDOUTを返します。したがって、3秒後、提供されたURLが不正であることがわかります。

  2. フィルタが存在しないIPアドレスへのソケットを作成し、それを接続しようとすると、SOCKET_ERRORを返す前に約10秒間ハングします。したがって、IPがネットワーク上に存在しない場合、_SO_RCVTIMEO_は無視されます...

質問:2番目のケースでは、存在しないIPのタイムアウトを設定するにはどうすればよいですか? IPが存在するかどうかを確認するために最初にICMPPINGを送信する必要がありますか、それともそのような他のチェックを実行する必要がありますか?

どんな助けでもありがたいです。ありがとう。 :)

私の問題への答え

ブロッキングソケットを使用しているため、接続が確立されるまで、またはホストが応答しないために接続が失敗するか、接続を拒否するまで、connect()ブロックを呼び出します。ソケットのタイムアウトを3秒に設定し、存在しないホストに接続しようとすると、PC(クライアント)はSYNフラグが設定されたTCPパケットを送信して、スリーウェイハンドシェイク。通常、ホストは、起動している場合、ACKおよびSYNフラグが設定されたTCPパケットで応答し、クライアント(me)はACKフラグが設定されたTCPパケットを送信します。次に、接続が確立されます。ただし、ホストがダウンしていてSYNが送信された場合、クライアントは3秒のタイムアウトが経過するまで待機してから、TcpMaxConnectRetransmissionsMicrosoft ARTICLE )レジストリ設定に達するまでAGAINとAGAINを試行します。ホストは稼働している可能性がありますが、SYNパケットが失われる可能性があります...私のWindowsXPはこの設定が4になっていると思います。したがって、SYNを送信しようとするたびに、3秒間待機し、 4回目の試行は失敗し、_SOCKET_ERROR_(12秒後)を返し、最後のWSAエラーとしてWSAETIMEDOUTを設定します。

これを回避する方法は、非ブロッキングソケットを使用し、Martin Jamesが提案したように、接続試行時間を手動で測定しようとすることです(現在、connect()はブロックされないため)。

別の方法は、最後の手段であるレジストリをいじることです...

17
Cipi

弾丸をかみます。リモートIPがPINGサーバーを実行していないか、PINGが一部のルーターによってブロックされている可能性があるため、役に立ちません。 10秒間待ってから、使用するエラー表示を行うことはできませんか?

試行された接続を3秒後に絶対にタイムアウトする必要がある場合は、自分でタイムアウトすることができます。

2
Martin James

実際、バークレーソケットには接続のタ​​イムアウトがないため、設定できません。 ICMP PINGは役に立ちません。理由はわかりませんが、ホストが存在しない場合は、PINGで約1秒を費やします。ホストが存在することを検出するためにARPを使用してみてください。

1
xandox

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;
} 
0
steveh