2

デッド tcp ソケット (ワイヤのプラグが抜かれたことが原因) を閉じると、別の通常の開いている tcp ソケットに影響を与えるという奇妙な問題に直面しています。以下は詳細情報です:

  1. トポロジ
    クライアント A ←→ スイッチ A ← ルーター A:NAT ← .. ネットワーク .. → ルーター B:NAT → スイッチ B ←→ サーバー B

  2. 問題:
    クライアントとサーバーの間で、ワイヤーのプラグを抜いたために切断された接続があるとします。(マシンとスイッチの間の) ケーブルを抜いた後、別のマシンからクライアント 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 は問題ありません。

4

1 に答える 1

2

うわー、なんという難問。私は可能な答えを持っていると思います。そして、私はその意味合いがあまり好きではありませんが、標準を見ると避けられないと思います(これはウィキペディアの簡略化です)。

NAT (および特にフルコーン) は、クライアントが到達しようとしている外部アドレスと一致するように、クライアントに内部アドレス (IP とポート) を与えることによって機能します。戻りトラフィックはすべて内部アドレスに送信され、ルーターによって外部アドレスに転送されます。

例を使用して、この簡単な説明を拡張し、これが何を意味するかを示しましょう...

ポート 80 を内部サーバーに転送する NAT ゲートウェイがあるとします。内部宛先もポート 80 です。ゲートウェイには外部 IPn.n.n.nと内部 IPがありますy.y.y.y

クライアントn.n.n.n:80が NAT サーバーに接続すると、要求は忠実に に転送されますy.y.y.y:80が、その過程で IP フレームが書き換えられます。送信者アドレスは NAT ゲートウェイの内部 IP になり、送信者ポートはクライアントが書き込んだものではなくなり、NAT ゲートウェイによって割り当てられた新しいポートになります。

はい、新しいポートはNATゲートウェイによって割り当てられます。ただし、クライアント IP とアクセスしようとしたポート (この場合は 80) の関数として割り当てられます。

すべてうまくいっていますが... クライアントが 2 番目の接続を確立すると、同じマッピング関数が使用されます。これは問題になりませんか?まあそれはできます。ゲートウェイが異なるクライアント アドレスを区別しない場合 (理想的には、クライアントからの各接続には一意のポートが必要です)、古い接続で作成されたマッピングを単純に上書きします。

したがって、古いソケットからの再送信トラフィックがクライアントの新しいソケットに送信されます。

非常に望ましくありませんが、NAT の実装方法によっては可能です。そして、それはNATの問題のようです-直接接続すると表示されません...

さて、私の説明には既に穴があります。つまり、これは、同じサーバーに対して同時に 2 つのソケットを開くことはできないということです。これが機能すると私が考えることができる唯一の理由は、ソケットがまだ開いているためです。したがって、ゲートウェイはソケットが死んでいるとは見なさず、そのクライアントの 2 番目のマッピングを作成します。

少なくともある程度の意味があったことを願っています。

于 2013-03-18T22:12:24.680 に答える