11

私たちは、非常に単純なネットワーク通信を行うためのクライアントとサーバーを作成しています(私が思っていたのは)。複数のクライアントがサーバーに接続し、サーバーは他のすべてのクライアントにデータを送り返すことになっています。

selectサーバーは、トラフィックを待機するブロッキングループ内にあり、トラフィックが発生すると、他のクライアントにデータを送信します。これは問題なく機能するようです。

問題はクライアントです。読み取りに応答して、書き込みを実行したい場合があります。

ただし、次を使用すると、次のことがわかりました。

 rv = select(fdmax + 1, &master_list, NULL, NULL, NULL);

読み取る新しいデータができるまで、コードはブロックされます。ただし、(非同期で、別のスレッドから)ネットワーク通信スレッドに書き込む新しいデータがある場合があります。したがって、selectを定期的にウェイクアップして、次のように書き込むデータがあるかどうかを確認させます。

if (select(....) != -1)
{
  if (FD_SET(sockfd, &master_list))
     // handle data or disconnect
  else
     // look for data to write and write() / send() those.
}

選択をポーリングモード(または途方もなく短いタイムアウト)に設定してみました:

// master list contains the sockfd from the getaddrinfo/socket/connect seq
struct timeval t;
memset(&t, 0, sizeof t);
rv = select(fdmax + 1, &master_list, NULL, NULL, &t);

しかし、その場合、クライアントは受信データを取得しないことがわかりました。

また、次のように、ソケットfdを非ブロッキングに設定してみました。

fcntl(sockfd, F_SETFL, O_NONBLOCK);

しかし、それは問題を解決しません:

  1. クライアントにデータselect()がない場合、struct timevalデータの読み取りは機能しますが、ブロックを解除して書き込み可能なデータを検索できるようにすることはありません。
  2. クライアントselect()timevalポーリングを取得する必要がある場合、読み取るデータが着信していることを通知することはなく、ネットワーク接続が確立されていないとアプリがフリーズします(他のすべての関数呼び出しが成功したにもかかわらず)

私が間違っている可能性があることについてのポインタはありますか?同じソケットで読み取り/書き込みを行うことはできませんか(それが真実であるとは信じられません)。

(編集:正解、およびサーバーでは覚えているがクライアントでは覚えていないことは、2番目のfd_setを用意し、select()を呼び出す前にmaster_listをコピーすることです。

// declare and FD_ZERO read_fds:
// put sockfd in master_list

while (1)
{
   read_fds = master_list;
   select(...);

   if (FD_ISSET(read_fds))
     ....
   else
     // sleep or otherwise don't hog cpu resources
}

)。

4

4 に答える 4

12

あなたがする行を除いて、すべてがうまく見えますif (FD_SET(sockfd, &master_list))。私は非常によく似たコード構造を持っており、を使用しFD_ISSETました。リストが設定されているかどうかをテストすることになっていますが、再度設定することはできません。それ以外は何も見えません。

編集。また、タイムアウトには次のものがあります。

timeval listening_timeout;
listening_timeout.tv_sec = timeout_in_seconds;
listening_timeout.tv_usec = 0;

0に設定すると問題が発生する可能性があります(実行しているように見えますか?)

編集2。選択が終了した後、再度入力する前に読み取りセットをクリアしていなかったときに、奇妙な問題が発生したことを思い出しました。私は次のようなことをしなければなりませんでした:

FD_ZERO(&sockfd);
FD_SET(sockfd, &rd);

私が入る前にselect。でも理由は思い出せません。

于 2010-01-14T10:23:17.677 に答える
7

選択呼び出しで記述子に追加されるネットワークスレッドとメインスレッドの間で読み取り/書き込みファイル記述子を作成して共有することについてのトリックを思い出しているようです。このfdには、送信するものがある場合にメインスレッドによって1バイトが書き込まれます。書き込みはselect呼び出しからネットワークスレッドをウェイクアップし、ネットワークスレッドは共有バッファからデータを取得してネットワークに書き込み、selectでスリープ状態に戻ります。

それが少し曖昧でコードが不足している場合は申し訳ありません...そして私の記憶が間違っている可能性があります..他の人があなたをさらに案内しなければならないかもしれません。

于 2010-01-14T10:27:35.750 に答える
1

コードに問題はないので、動作するはずです。それを機能させることができない場合、それを回避する1つの方法は、読み取りスレッドと書き込みの準備をするスレッドで使用されるパイプを作成し、パイプの読み取り端をselectセットに追加することです。次に、他のスレッドが書き込むデータを準備すると、パイプに何かを送信するだけで、読み取りスレッドがからウェイクアップされselect、書き込みを実行できるようになります。読み取りまたは書き込みするデータの頻度によっては、これもより効率的である可能性があります。

于 2010-01-14T10:29:03.313 に答える
0

2つのスレッドが一度に同じソケットで動作できる必要があるため、メインスレッドはクライアントに書き込み可能であり、もう1つのスレッドは選択して着信データを待機している必要があります。もちろん、これは両方のスレッドがクライアントリストにアクセスできることを前提としています。

于 2010-03-09T00:13:22.480 に答える