5
while (xxx) {
    timeout.tv_sec=TIMEOUT;
    timeout.tv_usec=0;
    FD_ZERO(&set); 
    FD_SET(sd,&set);

    switch (select(FD_SETSIZE,&set,NULL,NULL,&timeout))
    xxxxx
}

ただし、正常に動作します

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

while (xxx) {
    timeout.tv_sec=TIMEOUT;
    timeout.tv_usec=0;

    switch (select(FD_SETSIZE,&set,NULL,NULL,&timeout))
    xxxxx
}

しません。最初は機能しますが、次回 while ループを実行すると、sd ソケットがデータを受信して​​もタイムアウトになります。毎回セットを空にしていっぱいにしなければならないのは、リソースの無駄のように思えます。

なぜこれが良いのか、さらに良いのは、おそらくそれを回避する方法を提案している人はいますか?

4

3 に答える 3

12

select はその引数を変更します。本当に毎回再初期化する必要があります。

オーバーヘッドが気になる場合、カーネルで完全な FD_SET を処理するコストは、FD_ZERO のコストよりもいくらか重要です。カーネル処理を最小限に抑えるために、FD_SETSZIZE ではなく、最大 fd のみを渡したいと思うでしょう。あなたの例では:

switch (select((sd + 1),&set,NULL,NULL,&timeout))

複数の fd を使用するより複雑なケースでは、通常、max 変数を維持することになります。

FD_SET(sd,&set);
if (sd > max) max = sd;
... repeat many times...

switch (select((max + 1),&set,NULL,NULL,&timeout))


多数のファイル記述子があり、それらを処理するオーバーヘッドが懸念される場合は、select() の代替手段をいくつか検討する必要があります。使用しているOSについては言及していませんが、UnixライクなOSにはいくつかあります:

  • Linux の場合、epoll()
  • FreeBSD/NetBSD/OpenBSD/MacOS X の場合、kqueue()
  • Solaris の場合、/dev/poll

API は異なりますが、基本的にすべて、一連のアクティブなファイル記述を維持するためのステートフル カーネル インターフェイスです。fd がセットに追加されると、その fd のイベントが通知されます。

于 2008-11-13T04:03:04.067 に答える
7

select の man ページを読んでください。返されるセットは、すぐに使用できるファイル記述子のみです。FD_ISSET を使用して、設定されているかどうかをそれぞれ確認することになっています。

fd_set は、使用する直前に必ず初期化してください。

于 2008-11-12T23:28:22.220 に答える
0

それがselectの仕組みです。ソケットが複数ある場合に最適であり、より理にかなっています。それがポイントです。多くのソケットを選択しています。1 つのソケットから読み取りたい場合は、読み取りまたは受信するだけです。

于 2008-11-12T23:29:49.687 に答える