web-dev-qa-db-ja.com

accept()とselect()を同時に使用しますか?

イベント駆動型のネットワークサーバープログラムがあります。このプログラムは、他のホスト上の他のプロセスからの接続を受け入れます。同じリモートIP上の異なるポートからの短期間の接続が多数存在する可能性があります。

現在、while(1)を呼び出して新しい接続を処理するスレッドを生成するaccept()ループがあります。メッセージが読み取られた後、各接続は閉じられます。リモートエンドでは、メッセージが送信された後、接続が閉じられます。

オープンソケットFDをキャッシュすることにより、接続のセットアップと切断のオーバーヘッドを排除したいと思います。送信者側では、これは簡単です。接続を閉じずに、接続を維持します。

受信機側では、少し難しいです。 accept()によって返されたFDを構造体に格納し、poll()またはselect()を使用して、そのようなすべてのソケットでメッセージをリッスンできることはわかっていますが、両方を同時に実行したいaccept()andを介して新しい接続をリッスンします。キャッシュされたすべての接続をリッスンします。

1つはpoll()で、もう1つはaccept()で2つのスレッドを使用する場合、accept()呼び出しが戻ったとき(新しい接続が開かれたとき)、ウェイクアップする必要があります古い接続セットを待機している他のスレッドを起動します。シグナルとpselect()を使用してこれを実行できることはわかっていますが、この混乱全体は、非常に単純なものにはあまりにも多くの作業のように思えます。

開かれている新しい接続と古い接続で送信されているデータを同時に処理できるようにする呼び出しまたは優れた方法論はありますか?

20
Borealid

前回チェックしたときは、ソケットでlistenを実行してから、selectまたはpollで接続が確立されたかどうかを確認できます。接続が確立された場合は、acceptで確認できます。 ;それはブロックしません(しかしあなたは したいかもしれません本当にすべきです念のためにO_NONBLOCKを設定してください)

23
mvds

リッスンを使用してから選択またはポーリングを使用してから受け入れることができます

if (listen (socket_fd, Number_connection) <0 )
{
    perror("listen");
    return 1;
}
fd_set set;
struct timeval timeout;
int rv;
FD_ZERO(&set); /* clear the set */
FD_SET(socket_fd, &set); /* add our file descriptor to the set */

timeout.tv_sec = 20;
timeout.tv_usec = 0;

rv = select(socket_fd + 1, &set, NULL, NULL, &timeout);
if(rv == -1)
{
    perror("select"); /* an error accured */
    return 1;
}
else if(rv == 0)
{
    printf("timeout occurred (20 second) \n"); /* a timeout occured */
    return 1;
}
else
    client_socket_fd = accept (socket_fd,(struct sockaddr *) &client_name, &client_name_len);
5
Khaled

物事を台無しにしないために、リスナーを別のプロセス(スレッド)に配置します。そして、既存のソケットを処理するために別のワーカープロセスを実行します。ノンブロッキングリスナーは本当に必要ありません。また、2つのスレッドを実行するスレッドオーバーヘッドはありません。

それはそのように機能するはずです:クライアントソケットの記述子を返すまでリスナースレッドを受け入れ、それをすべてのダーティな読み取り/書き込みジョブを実行しているワーカーに渡します。

複数のポートをリッスンし、リスナーごとに1つのプロセスを保持したくない場合は、ソケットをO_NONBLOCKに設定し、次のようにすることをお勧めします。

// loop through listeners here and poll'em for read, when read is successful call accept, get descriptor, pass it to worker and continue listen
    while(1){
        foreach( serverSocket in ServerSockets ){
             if( serverSocket.Poll( 10, SelectRead ) ){
                  clientSocket = serverSocket.Accept();
                  // pass to worker here and release
             }

        }
    }
0
hoodoos