8

2 つのホスト間で udp でノンブロッキング読み取りを使用すると、メッセージが見つからないという問題があります。送信者は Linux 上にあり、リーダーは winxp 上にあります。Python のこの例は、問題を示しています。
問題を示すために使用される 3 つのスクリプトを次に示します。
send.py :

import socket, sys
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
host = sys.argv[1]
s.sendto('A'*10,   (host,8888))
s.sendto('B'*9000, (host,8888))
s.sendto('C'*9000, (host,8888))
s.sendto('D'*10,   (host,8888))
s.sendto('E'*9000, (host,8888))
s.sendto('F'*9000, (host,8888))
s.sendto('G'*10,   (host,8888))

read.py

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('',8888))
while True:
    data,address = s.recvfrom(10000)
    print "recv:", data[0],"times",len(data) 

read_nb.py

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('',8888))
s.setblocking(0)
data =''
address = ''
while True:
    try:
        data,address = s.recvfrom(10000)
    except socket.error:
        pass
    else: 
        print "recv:", data[0],"times",len(data) 

例 1 (問題なく動作):

ubuntu> python send.py
winxp > read.py

read.py からこの ok の結果を取得します。

recv: A×10
recv: B×9000
recv: C×9000
recv: D×10
recv: E×9000
recv: F×9000
recv: G×10

例 2 (メッセージの欠落):
この場合、短いメッセージが read_nb.py によって捕捉されないことがよくあります。

ubuntu> python send.py
winxp > read_nb.py

read_nb.py から次の結果を取得します。

recv: A×10
recv: B×9000
recv: C×9000
recv: D×10
recv: E×9000
recv: F×9000

上記は最後の 10 バイトのメッセージがありません

以下は、中央が欠落している 10 バイトのメッセージです。

recv: A×10
recv: B×9000
recv: C×9000
recv: E×9000
recv: F×9000
recv: G×10

Windows で Wireshark を使用して確認したところ、すべてのメッセージがキャプチャされるたびにホスト インターフェイスに到達しますが、read_nb.py によってキャプチャされません。説明は何ですか?

また、Linux で read_nb.py を、Windows で send.py を試してみたところ、動作しました。したがって、この問題はwinsock2と関係があると思います

または、ノンブロッキング udp を間違った方法で使用している可能性がありますか?

4

2 に答える 2

8

データグラムが(wiresharkログに示されているように)ホストに到達している場合、最初に確認するのは、ソケットrecvバッファーのサイズであり、可能な限り大きくし、可能な限り高速に実行します。

もちろん、これはUDPでは完全に予想されます。データグラムは、いつでも、どのような理由でも破棄される可能性があると想定する必要があります。また、データグラムを複数回取得する場合があります...

信頼性が必要な場合は、独自に構築するか、TCPを使用する必要があります。

于 2010-10-18T16:23:57.813 に答える
8

UDPではメッセージが失われるのは正常です。トランスポート層はデータグラムの順序や配信を保証しません。それらを順番に、および/または常に配信したい場合は、TCPに切り替えるか、シーケンス処理および/またはack/タイムアウト/再送信を自分で実装してください。

あなたの例では、大きなメッセージは、1500の通常のイーサネットMTUから8バイトのUDPヘッダーを引いたものよりも大きいため(ジャンボフレームを使用している場合を除く)、送信者によってフラグメント化されます。これにより、送信者と受信者の両方により多くの負荷がかかりますが、完全なデータグラムが到着するまでカーネルメモリにフラグメントを保持する必要があるため、受信者により多くの負荷がかかります。

受信バッファが36030バイトでオーバーフローしているとは思えませんが、Windowsでネットワークを構築することは決してないので、SO_RECVBUF@Lenが提案するように受信機のソケットオプションの値を確認することをお勧めします。

また、の出力をチェックしてnetstat -s、ドロップされたパケット数を確認します。

于 2010-10-18T20:40:57.433 に答える