私たちは、非常に単純なネットワーク通信を行うためのクライアントとサーバーを作成しています(私が思っていたのは)。複数のクライアントがサーバーに接続し、サーバーは他のすべてのクライアントにデータを送り返すことになっています。
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);
しかし、それは問題を解決しません:
- クライアントにデータ
select()
がない場合、struct timeval
データの読み取りは機能しますが、ブロックを解除して書き込み可能なデータを検索できるようにすることはありません。 - クライアント
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
}
)。