0

に接続されているserver2 つの接続SOCKETがあり、メッセージの送受信時に停止しないノンブロッキング モードclientsに設定しました。server各接続のタイムアウトを設定したいのですSOCKETが、次のコードを使用すると:

 void getMessage(SOCKET connectedSocket, int time){ 
    string error = R_ERROR;
    // Using select in winsock
    fd_set  set;
    timeval tm;

    FD_ZERO(&set);
    FD_SET(connectedSocket, &set);

    tm.tv_sec = time; // time 
    tm.tv_usec = 0; // 0 millis
    switch (select(connectedSocket, &set, 0, 0, &tm))
    {
    case 0:
        // timeout
        this->disconnect();
        break;
    case 1:
        // Can recieve some data here
        return this->recvMessage();
        break;
    default:
        // error - handle appropriately.
        break;
    }
return error;
}

私のサーバーはノンブロッキングモードではなくなりました! 2 番目の接続からメッセージを取得するには、1 番目の接続のタイムアウトが終了するまで待たなければなりません。それは私が期待するものではありません!では、ノンブロッキング モードのタイムアウトを設定する方法はありますか? それとも自分で処理する必要がありますか?

4

1 に答える 1

4

selectは逆多重化メカニズムです。単一のソケットまたはタイムアウトでデータの準備ができているかどうかを判断するために使用していますが、実際には多くのソケットでデータの準備完了ステータスを返すように設計されています (したがってfd_set)。概念的には 、 、 とpoll同じepollですkqueue。これらのメカニズムをノンブロッキング I/O と組み合わせることで、アプリケーション作成者は単一スレッドの並行サーバーを実装するためのツールを利用できます。

私の意見では、あなたのアプリケーションはそのような力を必要としません。アプリケーションは 2 つの接続のみを処理し、接続ごとに 1 つのスレッドを既に使用しています。ソケットをブロッキング I/O モードのままにしておく方が適切だと思います。

非ブロッキング モードを主張する場合は、select呼び出しを別のものに置き換えることをお勧めします。必要なselectのは、単一のソケットの読み取り準備またはタイムアウトの指標であるため、recv適切なパラメーターを渡してソケットに適切なタイムアウトを設定することで、同様の効果を得ることができます。

tm.tv_sec = time;
tm.tv_usec = 0;
setsockopt(connectedSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tm, sizeof(tm));
char c;
swtich (recv(connectedSocket, &c, 1, MSG_PEEK|MSG_WAITALL)) {
case -1:
    if (errno == EAGAIN) {
        // handle timeout ...
    } else {
        // handle other error ...
    }
    break;
case 0: // FALLTHROUGH
default:
    // handle read ready ...
    break;
}

からman recv:

MSG_PEEK -- このフラグにより​​、受信操作は、キューからデータを削除せずに、受信キューの先頭からデータを返します。したがって、後続の受信呼び出しは同じデータを返します。

MSG_WAITALL (Linux 2.2 以降) -- このフラグは、完全な要求が満たされるまで操作をブロックすることを要求します。ただし、シグナルがキャッチされた場合、エラーまたは切断が発生した場合、または次に受信するデータが返されたデータとは異なるタイプである場合、呼び出しは要求されたよりも少ないデータを返すことがあります。

なぜselectあなたが観察したように振る舞っているのかについて。呼び出しはスレッドセーフですが、select再入可能性に対して完全に保護されている可能性があります。そのため、あるスレッドの への呼び出しselectは、別のスレッドの呼び出しが完了した後にのみ着信します (への呼び出しselectはシリアル化されます)。これは、デマルチプレクサとしての機能と一致しています。その目的は、接続の準備ができている単一のアービターとして機能することです。そのため、単一のスレッドによって制御される必要があります。

于 2012-06-13T06:27:43.613 に答える