質問

fd_setを繰り返す簡単な方法があるのだろうか? select()がこれらのfd_setsを変更して興味のあるもののみを含めるために、接続されたすべてのソケットをループする必要がない理由は、これをやりたい理由です。また、直接アクセスすることを意図していないタイプの実装を使用することは、システムによって異なる可能性があるため、一般に悪い考えであることも知っています。しかし、これを行うには何らかの方法が必要であり、アイデアが不足しています。だから、私の質問は次のとおりです。

fd_setを繰り返して反復しますか?これが本当に悪い習慣である場合、すべての接続されたソケットをループすることを除いて、私の「問題」を解決する他の方法はありますか?

ありがとう

役に立ちましたか?

解決

セットのファイル記述子に対応するビットを選択する選択を選択します。したがって、少数だけに興味がある(他の人を無視できる)に関心がある場合は、すべてのFDSを反復する必要はありません。 。

if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
   perror("select");
   exit(4);
}

if(FD_ISSET(fd0, &read_fds))
{
   //do things
}

if(FD_ISSET(fd1, &read_fds))
{
   //do more things
}

編集
これがFD_SET構造体です:

typedef struct fd_set {
        u_int   fd_count;               /* how many are SET? */
        SOCKET  fd_array[FD_SETSIZE];   /* an array of SOCKETs */
} fd_set;

ここで、fd_countはセットの数の数です(したがって、これを使用して最適化を追加できます)、fd_arrayはビットベクトルです(size fd_setsize * sizeof(int) これは機械に依存します)。私のマシンでは、64 * 64 = 4096です。

それで、あなたの質問は本質的に:ビットベクトル(サイズ4096ビット)で1のビット位置を見つける最も効率的な方法は何ですか?

ここで一つのことをクリアしたい:
「接続されたすべてのソケットをループする」という意味では、実際に接続に物を読んだりしたりしているというわけではありません。 fd_isset()は、接続の割り当てられたfile_descriptor番号に配置されているFD_SETのビットをチェックするだけです。効率があなたの目的である場合、これが最も効率的ではありませんか?ヒューリスティックを使用しますか?

この方法の何が問題なのか、そして代替方法を使用して何を達成しようとしているのか教えてください。

他のヒント

Select()を呼び出す前にFD_SET構造体に入力する必要があります。元のSTD ::ソケットのセットを直接渡すことはできません。 [SELECT()次に、FD_SETをそれに応じて変更して、「設定」されていないソケットを削除し、残っているソケットの数を返します。 STD ::セットではなく、結果のFD_SETをループする必要があります。結果のFD_SETには、準備ができている「セット」ソケットのみが含まれているため、FD_ISSET()を呼び出す必要はありません。

fd_set read_fds;
FD_ZERO(&read_fds);

int max_fd = 0;

read_fds.fd_count = connected_sockets.size();
for( int i = 0; i < read_fds.fd_count; ++i ) 
{
    read_fds.fd_array[i] = connected_sockets[i];
    if (read_fds.fd_array[i] > max_fd)
      max_fd = read_fds.fd_array[i];
}

if (select(max_fd+1, &read_fds, NULL, NULL, NULL) > 0)
{ 
    for( int i = 0; i < read_fds.fd_count; ++i ) 
        do_socket_operation( read_fds.fd_array[i] ); 
} 

fd_isset()がより頻繁に再生される場所は、select()でエラーチェックを使用する場合です。

fd_set read_fds;
FD_ZERO(&read_fds);

fd_set error_fds;
FD_ZERO(&error_fds);

int max_fd = 0;

read_fds.fd_count = connected_sockets.size();
for( int i = 0; i < read_fds.fd_count; ++i ) 
{
    read_fds.fd_array[i] = connected_sockets[i];
    if (read_fds.fd_array[i] > max_fd)
      max_fd = read_fds.fd_array[i];
}

error_fds.fd_count = read_fds.fd_count;
for( int i = 0; i < read_fds.fd_count; ++i ) 
{
    error_fds.fd_array[i] = read_fds.fd_array[i];
}

if (select(max_fd+1, &read_fds, NULL, &error_fds, NULL) > 0)
{ 
    for( int i = 0; i < read_fds.fd_count; ++i ) 
    {
        if( !FD_ISSET(read_fds.fd_array[i], &error_fds) )
            do_socket_operation( read_fds.fd_array[i] ); 
    }

    for( int i = 0; i < error_fds.fd_count; ++i ) 
    {
        do_socket_error( error_fds.fd_array[i] ); 
    }
} 

それはかなり簡単です:

for( int fd = 0; fd < max_fd; fd++ )
    if ( FD_ISSET(fd, &my_fd_set) )
        do_socket_operation( fd );

このループはの制限です select() インターフェース。基礎となる実装 fd_set 通常、少し設定されています。これは、明らかにソケットを探すにはビットをスキャンする必要があることを意味します。

まさにこのため、いくつかの代替インターフェイスが作成されたのは、残念ながら、すべてOS固有です。たとえば、Linuxが提供します epoll, 、アクティブなファイル記述子のみのリストを返します。 FreeBSDとMac OS Xの両方が提供されます kqueue, 、同じ結果を達成します。

のこのセクション7.2を参照してください beej「ネットワーキングのガイド - '7.2。 select() - fd_issetを使用してsynchronous i/o多重化 '。

要するに、ファイル記述子が読み取り/書き込みの準備ができているかどうかを判断するために、FD_SETを繰り返す必要があります...

あなたがやろうとしていることは良い考えだとは思わない。

まず、システムに依存していますが、あなたはすでにそれを知っていると思います。

第二に、内部レベルでは、これらのセットは整数の配列として保存され、FDはセットビットとして保存されます。 Select the FD_Setsizeは1024です。繰り返して興味のあるFDを取得したい場合でも、ビット操作の混乱とともにその数をループする必要があります。したがって、FD_Setsize FDを選択しているのを待っていない限り、私はそうではないと思いますが、それは良い考えではありません。

えっ、ちょっと待って!!。いずれにせよ、それは良い考えではありません。

私はあなたがそれを使って多くのことができるとは思わない select() 効率的に電話してください。での情報「C10Kの問題「まだ有効です。

プラットフォーム固有のソリューションが必要です。

または、イベントライブラリを使用してプラットフォームの詳細を隠すこともできます libev

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top