6

私はソケットプログラミングが初めてで、それがどのように機能するかを完全に理解しようとしていますが、今のところ私はselect().

問題は、私のコードでは、select がアクティビティを検出し、fd が設定されたままにFD_ISSETなると、select 関数を無視するように、次の反復で自動的に true が返されるように見えることです。問題はこれと同じようですが、そこで見つけたすべてのことを行いましたが、役に立たなかった: http://compgroups.net/comp.unix.programmer/how-does-fd_isset-return-0-after-returne /55058

私はLinuxを使用しているため、後でtimeval変数を再初期化するようにしました。select()この関数はOSごとに異なる動作をすることを理解していたため、selectの前FD_ZEROと前にfdセットも再初期化しました。FD_SET

私は何を間違っていますか?コードは次のとおりです。

#include <stdio.h>
#include <strings.h>

#include <sys/select.h>
#include <sys/time.h>

int main () {
  struct timeval tv;

  tv.tv_sec = 5; // 5 seconds timeout
  tv.tv_usec = 0;

  fd_set afds, rfds;

  FD_ZERO(&afds);
  FD_SET(0, &afds);

  while (1) {
    rfds = afds;
    select(1, &rfds, NULL, NULL, &tv);
    // linux, reinitialize tv?
    tv.tv_sec = 5;
    tv.tv_usec = 0;

    // so at this point after select runs the first time and detects STDIN activity
    // it will enter an infinite loop printing "fd 0 is set" (why?)
    if (FD_ISSET(0, &rfds)) {
      printf("fd 0 is set\n");
      FD_CLR(0, &rfds);
    } else {
      printf("fd 0 is NOT set\n");
    }
  }
}

私は新しいユーザーであり、これに答えることができないため、質問を編集します。

実際のところ、afds の値が割り当てられるときは select の前に rfds を初期化します。この値は常に FD_ZERO(&afds); で設定されます。FD_SET(0, &afds); これはまだ私にはうまくいきません。

これが私が理解していることです:

  1. afds に stdin ファイル記述子を追加します

  2. while 無限ループ、rfds = afds に入ります (rfds はループの開始時に常に = afds になります)。

  3. また、このとき、FD_ISSET(0, &rfds) は常に != 0 になります。

  4. select には 5 秒のタイムアウトがあるため、この時点で 5 秒が経過する前に何も入力しないと終了します。UNSETTING FD_ISSET(0, &rfds) - 正しいですか? そのため、何も入力されていない場合、select は実際に fd 0 の設定を解除します。これはうまくいくようです

  5. タイムアウトのに何かを入力すると、問題が発生します。この時点で、FD_ISSET(0, &rfds) は != 0 を返し、fd 0 が設定されていることを出力し、各ループ fd が設定されます。

わかりました、これは正確ですか、私はそれを正しく理解しましたか? fd の準備ができて終了することを実際に検出し、fd != 0 を設定するため、実際には select は時間が経過するのを待ちません。

さらなる質問が必要です:サーバーが時々複数のクライアントに自動的にメッセージを送信する必要がある場合(クライアントから読み取ったものとは関係なく)、コードを適応させることで select と gettimeofday でそれを行うことは可能でしょうか?その上?

助けてくれてありがとう。

4

2 に答える 2

16

select()エッジトリガーではなく、レベルトリガーです。ファイル記述子のセットを渡すと、最近状態が変化したものだけでなく、現時点で読み取り可能/書き込み可能/例外的なものを通知します。

この場合、FD は呼び出しのたびに読み取り可能としてマークされます。これは、FD が表示されたときに (利用可能な入力を排出するなど) 読み取り不能select()にするために何もしていないためです

于 2013-01-23T17:20:22.613 に答える
6

fd_set に保存されている値は、select() が起動した後も残ります。アプリケーションでは、select() が多数のソケットを監視することができます。fd_set を自動的にクリーニングすると、複数のソケットにサービスが必要であることをまったく検出できなくなります。

select() が呼び出される前に各パスで fd_set がきれいに初期化されるように、無限ループ内で FD_ZERO() および FD_SET() を実行する必要があります。

于 2013-01-23T17:25:07.647 に答える