6

シンプルなクライアント/サーバーのセットアップがあります。サーバーは C 言語であり、サーバーにクエリを実行するクライアントは Java です。

私の問題は、接続を介して帯域幅を集中的に使用するデータ (ビデオ フレームなど) を送信すると、最大で半分のパケットがドロップされることです。サーバー側で udp パケットを適切にフラグメント化するようにします (udp の最大ペイロード長は 2^16 です)。サーバーがパケットを送信していることを確認しました (sendto() の結果を printf します)。しかし、Java は半分のデータを取得していないようです。

さらに、TCP に切り替えると、すべてのビデオ フレームが通過しますが、レイテンシーが増加し始め、数秒の実行時間の後に数秒の遅延が追加されます。

私が行方不明であることは明らかですか?私はこれを理解できないようです。

4

5 に答える 5

9

Wiresharkのようなネットワーク ツールを入手して、ネットワーク上で何が起こっているかを確認してください。

UDP は再送信を試行しないため、パケットがどこかでドロップされた場合、損失を処理するのはプログラム次第です。TCP は、すべてのパケットをプログラムに順番に配信するために懸命に働き、重複を破棄し、失われたパケットを独自に要求します。レイテンシーが高い場合は、サーバーからの再送信として表示される TCP でも多くのパケット損失が発生するはずです。TCP の再送信が見られない場合は、クライアントがデータを処理する速度が追いついていない可能性があります。

于 2010-03-14T02:04:18.387 に答える
3

UDP ベースのアプリケーション プロトコルは、必然的にパケット損失、並べ替え、および (場合によっては) 重複の影響を受けやすくなります。UDP の「U」は、Unreliable Datagram Protocol のように「Unreliable」を表す場合があります。(わかりました、それは実際には「ユーザー」の略です...しかし、UDPの特性を覚えるには確かに良い方法です。)

通常、UDP パケットの損失は、トラフィックがサーバーとクライアント間の 1 つまたは複数の「ホップ」のバッファ容量を超えているために発生します。これが発生すると、パケットがドロップされます...そしてUDPを使用しているため、これが発生しているというトランスポートプロトコルレベルの通知はありません.

アプリケーションで UDP を使用する場合、アプリケーションは UDP の信頼性の低い性質を考慮し、ドロップされたパケットや順不同のパケットを処理し、独自のフロー制御を行うための独自のメカニズムを実装する必要があります。(すでに過負荷になっているネットワークに影響を与える可能性があることを考慮せずに UDP パケットを爆発させるアプリケーションは、悪いネットワーク市民です。)

(TCP の場合、おそらくパケットもドロップされますが、TCP はドロップされたパケットを検出して再送信し、TCP フロー制御メカニズムが作動してデータ転送速度を低下させます。最終的な結果は「レイテンシー」です。 )

編集-OPのコメントに基づいて、彼の問題の原因は、クライアントが一定期間「リッスン」していなかったため、(おそらく)クライアントのOSによってパケットがドロップされたことです。これに対処する方法は次のとおりです。

  1. パケットを読み取り、処理のためにキューに入れる専用の Java スレッドを使用します。

  2. ソケットのカーネル パケット キューのサイズを増やします。

ただし、これらの対策を講じても、パケットがドロップされる可能性があります。たとえば、マシンが過負荷になっている場合、アプリケーションは、カーネルがパケットをドロップする前に、すべてのパケットを読み取ってキューに入れるのに十分な頻度で実行タイム スライスを取得できない可能性があります。

編集 2 - UDP が重複の影響を受けやすいかどうかについては、いくつかの議論があります。確かに、UDP には固有の重複検出または防止機能がありません。しかし、インターネットである IP パケット ルーティング ファブリックが自発的にパケットを複製する可能性が低いことも事実です。そのため、重複が発生した場合、送信者が UDP パケットを再送信することを決定したため、重複が発生する可能性があります。したがって、私の考えでは、UDP は重複の問題の影響を受けやすいですが、OS プロトコル スタックまたは IP ファブリックにバグがない限り重複を引き起こすことはありません。

于 2010-03-14T01:56:03.327 に答える
2

UDP は最大 65535 バイトの長さのパケットをサポートしますが ( 8 バイトの UDP ヘッダーを含みますが、注 1 を参照してください)、ユーザーと宛先の間の基本的なトランスポートは、その長さの IP パケットをサポートしていません。たとえば、イーサネット フレームの最大サイズは 1500 バイトです。これは、IP ヘッダーと UDP ヘッダーのオーバーヘッドを考慮すると、データ ペイロード長が約 1450 を超える UDP パケットは、複数の IP データグラムにフラグメント化される可能性が高いことを意味します。

最大サイズの UDP パケットは、少なくとも 45 個の個別の IP データグラムにフラグメント化されます。これらのフラグメントのいずれか失われると、UDP パケット全体が失われます。基礎となるパケット損失率が 1% の場合、アプリケーションの損失率は約 36% になります!

失われるパケットを減らしたい場合は、巨大なパケットを送信しないでください。各パケットのデータを約 1400 バイトに制限します (または、独自の「パス MTU 検出」を行って、断片化せずに安全に送信できる最大サイズを把握します)。 .


  1. もちろん、UDP にも IP の制限があり、IP データグラムの最大サイズは IP ヘッダーを含めて 65535 です。IP ヘッダーのサイズは 20 から 60 バイトの範囲であるため、UDP パケット内で転送可能なアプリケーション データの最大量は 65467 程度になる可能性があります。
于 2010-03-14T03:06:00.550 に答える
0

IPは、 20バイトの IP パケット ヘッダーを含む最大 65535 バイトのパケットをサポートします。UDPは、最大 65507 バイトのデータグラムに加えて、20 バイトの IP ヘッダーと8バイトの UDP ヘッダーをサポートします。ただし、ネットワーク MTU は実質的な制限です。これには、これらの 28 バイトだけでなく、イーサネット フレーム ヘッダーも含まれることを忘れないでください。フラグメント化されていない UDPの実際の実際の制限は、576 バイトの最小 MTU からすべてのオーバーヘッドを差し引いたものです。

于 2010-03-14T04:35:49.243 に答える
0

問題は、UDPSocket で送信バッファがいっぱいになることに関係している可能性があります。で示されるバイト数だけを一度に送信しますUDPSocket.getSendBufferSize()setSendBufferSize(int size)この値を増やすために使用します。

SO_SNDBUF の設定より大きい DatagramPacket を送信するために #send() が使用される場合、パケットが送信されるか破棄されるかは実装固有です。

于 2010-03-14T02:41:07.043 に答える