3

ローカル ゲーム サーバーをチェックする UDP ブロードキャスト プログラムを作成しようとしていますが、受信側で問題が発生しています。稼働中のサーバーの数は常に不明であるため、停止したときにのみ終了するループが必要です。したがって、このコードでは次のようになります。

while(1) // start a while loop
       {
     if(recvfrom(sd,buff,BUFFSZ,0,(struct sockaddr *)&peer,&psz) < 0) // recvfrom() function call
        {
            cout << red << "Fatal: Failed to receive data" << white << endl;
            return;
        }
     else
     {
            cout << green << "Found Server :: " << white;
            cout << yellow << inet_ntoa(peer.sin_addr), htons(peer.sin_port);
            cout << endl;
   }
       }

Ctrl + C を押すまで、この recvfrom() 関数を実行したいと思います。(関連する質問から) ハンドラーなどを設定しようとしましたが、それらはすべて複雑すぎるか、終了するだけの単純な関数です。デモンストレーションとしてのプログラム。これが私の問題です。プログラムは、接続を受信するまで recvfrom でハングアップするため (私の推測では)、特に入力を待機する機会はありません。これにうまく機能するイベントを設定するにはどうすればよいですか?

ありがとう!

4

2 に答える 2

2

CTRL-C ハンドラーでフラグを設定し、そのフラグをwhileループ内の条件として使用します。

ああ、システムコールがシグナルによって中断される可能性のあるPOSIXシステムを使用していない場合は、ソケットを非ブロックにして、たとえばselect(小さなタイムアウトで)データをポーリングすることをお勧めします。


Windows では、このようなスキームにはいくつかの問題があります。主な問題は、CTRL-C ハンドラーによって関数呼び出しを中断できないことです。代わりに、「ループ終了」フラグもチェックしながら、ループで受信するものがあるかどうかをポーリングする必要があります。

次のようなことができます。

bool ExitRecvLoop = false;

BOOL CtrlHandler(DWORD type)
{
    if (type == CTRL_C_EVENT)
    {
        ExitRecvLoop = true;
        return TRUE;
    }

    return FALSE;  // Call next handler
}

// ...

SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE);

while (!ExitRecvLoop)
{
    fd_set rs;
    FD_ZERO(&rs);
    FD_SET(sd, &rs);

    timeval timeout = { 0, 1000 };  // One millisecond

    if (select(sd + 1, &rs, NULL, NULL, &timeout) < 0)
    {
        // Handle error
    }
    else
    {
        if (FD_ISSET(sd, &rs))
        {
            // Data to receive, call `recvfrom`
        }
    }
}

これを機能させるには、ソケットを非ブロックにする必要がある場合があります (ioctlsocket方法については、関数を参照してください)。

于 2013-08-08T06:40:58.627 に答える