デッド tcp ソケット (ワイヤのプラグが抜かれたことが原因) を閉じると、別の通常の開いている tcp ソケットに影響を与えるという奇妙な問題に直面しています。以下は詳細情報です:
トポロジ
クライアント A ←→ スイッチ A ← ルーター A:NAT ← .. ネットワーク .. → ルーター B:NAT → スイッチ B ←→ サーバー B問題:
クライアントとサーバーの間で、ワイヤーのプラグを抜いたために切断された接続があるとします。(マシンとスイッチの間の) ケーブルを抜いた後、別のマシンからクライアント A にログインすると、クライアントとサーバーの間に新しい TCP 接続が確立され、この接続は問題ありません。サーバーから、tcpカーネルがまだデータを再送信している間にデッドtcp接続を閉じると、他のtcp接続が汚染されているように見え、クライアントからサーバーへの方向が利用できなくなり、クライアントから送信されたデータを意味することがわかりました接続を介してサーバーが受信することは決してありませんが、驚いたことに、サーバーからクライアントへの反対方向は問題ありません。サーバーから送信された同じ tcp ソケット データを介して、クライアント マシンに到達します。
しかし、死んだ接続の tcp データ送信が停止するまで (たとえば 2 時間) 待ってからソケットを閉じると、他の TCP 接続は正常なままになります。
この問題の詳細な手順は次のとおり
です。 1. ルーター A の背後にある 2 つのクライアントがあります。NAT。NAT はフルコーンです。
2. ルーター B:NAT の背後に Linux サーバーがあり、NAT はフルコーンですが、ここではポート転送を使用します。
3. 4 台のマシンと 2 台のクライアントが X、Y と答え、サーバーが S と言う。
4. X と Y がログインしてビデオ会議をセットアップすると、両方ともサーバーへの tcp 接続が作成され、チャネル CX とチャネル CY
5 であるとします。Y クライアントが実行されているマシンのケーブルを抜きます。チャネル CY は壊れています。そして死んだ。しかし、チャネル CX は OK のままです。
6. 4 番目のマシンから Y にログインし、X とのビデオ会議を再度セットアップします。これで、新しい TCP チャネルができました。CY2 とします。
結果:
ステップ 6 で、サーバーが切断された接続 -- CY -- を数分で閉じると、新しいチャネル CY2 は一方向になります -- クライアント Y から送信されたデータは、ACK パケットを含めてサーバーに到達できません。逆の詩でOKです。
サーバーが切断された接続 (CY) を 2 時間などの長い時間で閉じた場合、問題は発生しません。
この問題は、NAT を介して実行している場合にのみ発生します。少なくとも、同じ LAN 内でアプリケーションを実行している場合は再現しません (NAT を通過する必要はありません)。
なぜそれが起こるのか誰か知っていますか?
編集:
サーバー側では、ノンブロッキング TCP ソケットを使用してモデルを選択しています。
psuedocode:
//server
listenfd = socket(,SO_STREAM,);
localAddr.port = htons(8013);
localAddr.ip = inet_addr(INADDR_ANY);
bind(localAddr...)
listen(listenfd, 100);
...
//using select model
select(maxFd, &fdSet, NULL, NULL);
for(...)
{
if (FD_ISSET(listenfd))
{
fd = accept(...)
set_non_block(fd);
...
}
...
}
詳細情報:
1) 最初のマシンの接続 A: 192.168.10.4:13000 ←→ ... ← ルーター A:NAT ← -現在: PublicIP:8661 (ランダム)..ネットワーク .. → ルーター B:NAT (ポートへ) :8013、ポートフォワーディング) → ... ←→ サーバー B
2) 2 台目のマシンの接続 B: 192.168.10.7:13000 ←→ ... ← ルーター A:NAT ← -現在: from PublicIP:8777 (random)..Network .. → Router B:NAT (to port:8013,ポート転送) → ... ←→ サーバー B
3) ワイヤを抜くと、接続 A が無効になり、3 台目のマシンに新しい接続 C が作成されます: 192.168.10.10:13000 ←→ ... ← ルーター A:NAT ← -現在: from PublicIP:8869 (ランダム).. ネットワーク.. → Router B:NAT (to port:8013, Port Forwarding) → ... ←→ Server B
サーバーから接続 A を閉じると、接続 C は単方向になりますが、サーバーから 2 時間以内に接続 A を閉じると、接続 C は問題ありません。