3

SuSE Linux Enterprise Server 12.3 (x86_64)でマルチクライアント サーバー プログラムをCで作成しました。クライアントごとに 1 つのスレッドを使用してデータを受信して​​います。

私の問題は次のとおりです。
サーバーを実行するために1つの端末を使用telnetし、サーバーに(クライアントとして)他のいくつかの端末を使用しています。サーバーでクライアントからデータを受信するために使用しました。また、エラーrecv()の戻り値のチェックも適用しました。Conn. クローズオン& 通常動作それ以外. ではフラグを使用していません。 recv()-10recv()

通常、 とを使用して telnet セッションを閉じる (つまり、クライアントを切断する) と、プログラムは正常Ctrl+]に動作しますがclose、 を使用してクライアントを強制的に終了するとkill <pid>、サーバーは接続の切断を検出できません。

それを修正する方法は?

制約:クライアント側に条件を設定したくありません。サーバー側のみでこれを修正したいです。

4

3 に答える 3

4

SO_KEEPALIVEサーバーのソケットで有効にできます。

/* enable keep-alive on the socket */
int one = 1;
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one));

デフォルトでは、キープアライブが有効になっている場合、キープアライブ プローブが試行される前に、接続が 2 時間アイドル状態になっている必要があります。パラメータを調整することで、キープアライブ時間をもう少し積極的に調整TCP_KEEPIDLEできます。

int idletime = 120; /* in seconds */
setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &idletime, sizeof(idletime));

プローブが送信されると、相手側からの確認応答が期待されます。確認応答がある場合、アイドル タイマーが再び期限切れになるまで、プローブはサイレントのままになります。キープアライブ プローブは、プローブに対する確認応答が受信されない場合、既定では 75 秒ごとに再試行されます。TCP_KEEPINTVLオプションで調整可能です。このTCP_KEEPCNTオプションは、連続して何回失敗すると接続がドロップされるかを制御します。デフォルトでは、その数は 9 です。

これらのオプションは Linux で使用できます。BSD にも同様のオプションがありますが、名前が異なります。

于 2013-08-19T07:26:06.117 に答える
2

私のプログラムは、通常は Ctrl+] を使用して telnet セッションを閉じる (つまり、クライアントを切断する) だけで正常に動作しますが、kill を使用してクライアントを強制終了するか、ターミナルを閉じると、サーバーは接続の切断を検出できません。

いずれの場合も、クライアント ソケットは、telnet プロセスを破棄するときに、telnet またはカーネルによって閉じられます。サーバーは、リターン 0FINを引き起こすセグメントを受信する必要がありますrecv()(すべての保留中のデータがソケットから読み取られた後)。

からのすべてのリターン コードをrecv()正しく処理していない可能性があります。

于 2013-08-19T09:54:36.750 に答える
2

あなたができることは、ある種のタイムアウトを実装することだけです。クライアント自体が実際に切断しない限り、クライアントが切断されたことを確実に判断することはできません。最も近いのは、クライアントが何かを送信する必要があり、タイムリーに送信できなかったことに気付くことです。

理由については、TCP は IP 上のレイヤーにすぎません。2 台のコンピューターを実際に接続するものは何もありません。「接続」とは、別のマシンが存在し、TCP を使用して情報を交換することに同意したことを単に確認することです。「接続」の抽象化は、両側がルールに従って動作する限り保持されます。クライアントを強制的に強制終了すると、取引の終わりを保持できなくなるため、サーバーはハングしたままになります。

于 2013-08-19T07:10:17.137 に答える