【以前も似たようなことを質問しました。これはより焦点を絞ったバージョンです。]
クライアントのソケットの close() を「見る」のではなく、TCP ソケットでのサーバーの select() 呼び出しが一貫してタイムアウトになる原因は何ですか? クライアント側では、ソケットは通常の socket() で作成されたブロッキング ソケットであり、サーバーに正常に接続し、ラウンドトリップ トランザクションを正常に送信します。サーバー側では、ソケットは accept() 呼び出しによって作成され、ブロックされ、fork() によって子サーバー プロセスに渡され、最上位サーバーによって閉じられ、子サーバー プロセスによって正常に使用されます。最初のトランザクション。続いてクライアントがソケットを閉じると、子サーバー プロセスの select() 呼び出しは、ソケットの読み取り準備完了状態を示すのではなく、一貫して (1 分後に) タイムアウトします。select() 呼び出しは、読み取り可能状態のみを探します。
以下は、子サーバー プロセスでの単純化された論理的に同等の select() 使用コードです。
int one_svc_run(
const int sock,
const unsigned timeout)
{
struct timeval timeo;
fd_set fds;
timeo.tv_sec = timeout;
timeo.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(sock, &fds);
for (;;) {
fd_set readFds = fds;
int status = select(sock+1, &readFds, 0, 0, &timeo);
if (status < 0)
return errno;
if (status == 0)
return ETIMEDOUT;
/* This code not reached when client closes socket */
/* The time-out structure, "timeo", is appropriately reset here */
...
}
...
}
以下は、クライアント側での一連のイベントと論理的に同等です (エラー処理は示されていません)。
struct sockaddr_in *raddr = ...;
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
(void)bindresvport(sock, (struct sockaddr_in *)0);
connect(sock, (struct sockaddr *)raddr, sizeof(*raddr));
/* Send a message to the server and receive a reply */
(void)close(sock);
fork()、exec()、および system() は呼び出されません。コードはこれよりかなり複雑ですが、これは関連する呼び出しのシーケンスです。
Nagel のアルゴリズムにより、close() で FIN パケットが送信されない可能性はありますか?