9

私は、多数の「プレーヤー」を制御する必要がある「サーバー」を備えたLANベースのソリューションに取り組んでいます。選択したプロトコルはUDPです。これは、接続が必要なく、トラフィックが短いコマンドのみで構成されているためです。同期にはブロードキャストメッセージを、プレーヤーの個々のコマンドには単一のターゲットメッセージを組み合わせて使用​​したいと思います。

マルチキャストTCPは代替手段ですが、より複雑で、タスクに正確に適していないため、ハードウェアで十分にサポートされていないことがよくあります。

残念ながら、私は奇妙な問題に遭遇しています:

「sendto」を使用して特定のIPに送信された最初のデータグラムは失われます。 その後すぐに同じIPに送信されたデータグラムが受信されます。しかし、しばらく(数分)待つと、最初の「送信」が再び失われます。

ブロードキャストデータグラムは常に機能します。(同じコンピューターへの)ローカル送信は常に機能します。

オペレーティングシステムまたはルーター/スイッチには、IPアドレスからMACアドレスへの変換テーブルがあり、数分間使用しないと忘れられてしまい、残念ながらデータグラムが失われると思います。さまざまなルーター/スイッチハードウェアでその動作を観察できたので、私の疑いはWindowsネットワーク層です。

UDPは定義上「信頼性が低い」ことは知っていますが、物理的な接続が機能していて、すべてが明確に定義されている場合でも、パケットが失われる可能性があるとは信じられません。そうすれば、それは文字通り価値がないでしょう。

技術的には、UDPソケットを開いて、ポートとINADRR_ANYにバインドします。次に、「sendto」と「recvfrom」を使用しています。私は決して接続をしません-私は何人かのプレーヤーを持っているので私は接続したくありません。私の知る限り、UDPは接続しなくても機能するはずです。

私の現在の回避策は、ダミーのデータグラムをすべての特定のプレーヤーのIPに定期的に送信することです。これで問題は解決しますが、どういうわけか「満足のいくものではありません」

質問:誰かがその問題を知っていますか?それはどこから来たのですか?どうすれば解決できますか?

編集:

私はそれを次のテストプログラムに要約しました:

int _tmain(int argc, _TCHAR* argv[])
{
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
    SOCKET Sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    SOCKADDR_IN Local = {0};
    Local.sin_family = AF_INET;
    Local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    Local.sin_port = htons(1234);
    bind(Sock, (SOCKADDR*)&Local, sizeof(Local));
    printf("Press any key to send...\n");
    int Ret, i = 0;
    char Buf[4096];

    SOCKADDR_IN Remote = {0};
    Remote.sin_family = AF_INET;
    Remote.sin_addr.S_un.S_addr = inet_addr("192.168.1.12");  // Replace this with a valid LAN IP which is not the hosts one
    Remote.sin_port = htons(1235);

    while(true) {
        _getch();
        sprintf(Buf, "ping %d", ++i);
        printf("Multiple sending \"%s\"\n", Buf);

        // Ret = connect(Sock, (SOCKADDR*)&Remote, sizeof(Remote));
        // if (Ret == SOCKET_ERROR) printf("Connect Error!\n", Buf);
        Ret = sendto(Sock, Buf, strlen(Buf), 0, (SOCKADDR*)&Remote, sizeof(Remote));
        if (Ret != strlen(Buf)) printf("Send Error!\n", Buf);
        Ret = sendto(Sock, Buf, strlen(Buf), 0, (SOCKADDR*)&Remote, sizeof(Remote));
        if (Ret != strlen(Buf)) printf("Send Error!\n", Buf);
        Ret = sendto(Sock, Buf, strlen(Buf), 0, (SOCKADDR*)&Remote, sizeof(Remote));
        if (Ret != strlen(Buf)) printf("Send Error!\n", Buf);
        }
    return 0;

プログラムはUDPソケットを開き、キーストロークごとに3つのデータグラムを連続して特定のIPに送信します。WiresharkがUDPトラフィックを監視しながら実行し、キーを押し、しばらく待ってからもう一度キーを押します。リモートIPに受信機は必要ありません。黒でマークされた「到達不能」パケットを取得しないことを除いて、違いはありません。これはあなたが得るものです:

Wiresharkスナップショット

ご覧のとおり、最初の送信でIPのARP検索が開始されました。その検索が保留されている間、3つの連続した送信の最初の2つが失われました。2番目のキーストローク(IP検索が完了した後)は、3つのメッセージを適切に送信しました。これでメッセージの送信を繰り返すことができ、待つまで(アドレスの翻訳が再び失われるまで約1分)機能し、その後再びドロップアウトが表示されます。

つまり、UDPメッセージを送信するときに送信バッファがなく、保留中のARP要求があります。最後のメッセージを除いて、すべてのメッセージが失われます。また、「sendto」は正常に配信されるまでブロックされず、エラーは返されません。

それは私を驚かせ、少し悲しくします。それは、現在の回避策を実行するか、一度に1つのメッセージのみを送信して応答を待つACKシステムを実装する必要があることを意味します。これは簡単ではありません。より多くの、そして多くの困難を意味します。

4

4 に答える 4

16

他の人からの回答があった後、ずっと投稿していますが、直接関係があります。

宛先アドレス(または宛先のゲートウェイ)のARPエントリがない場合、WinsockはUDPパケットをドロップします。

したがって、その時点ではARPエントリがないため、最初のUDPパケットの一部がドロップされる可能性が非常に高くなります。他のほとんどのオペレーティングシステムとは異なり、winsockはARP要求の完了中に1パケットのみをキューに入れます。

これはここに文書化されています:

ARPは、指定された宛先アドレスの1つのアウトバウンドIPデータグラムのみをキューに入れますが、そのIPアドレスはMACアドレスに解決されます。UDPベースのアプリケーションが複数のIPデータグラムを単一の宛先アドレスに一時停止せずに送信する場合、ARPキャッシュエントリがまだ存在しないと、一部のデータグラムがドロップされる可能性があります。アプリケーションは、パケットのストリームを送信する前に、Iphlpapi.dllルーチンSendArp()を呼び出してARPキャッシュエントリを確立することにより、これを補うことができます。

MacOSXFreeBSDでも同じ動作が見られます。

インターフェイスがキャッシュにないアドレスのマッピングを要求すると、ARPはマッピングを必要とするメッセージをキューに入れ、アドレスマッピングを要求する関連する関連ネットワーク上でメッセージをブロードキャストします。応答が提供されると、新しいマッピングがキャッシュされ、保留中のメッセージが送信されます。ARPは、マッピング要求への応答を待機している間、最大で1つのパケットをキューに入れます。最近「送信された」パケットのみが保持されます。

于 2012-09-26T09:01:41.257 に答える
4

UDPパケットは受信時にバッファリングされることになっていますが、UDPパケット(またはそれを保持するイーサネットフレーム)は、特定のマシンのいくつかのポイントでドロップできます。

  1. ネットワークカードにそれを受け入れるのに十分なスペースがありません、
  2. OSネットワークスタックには、コピー先のバッファメモリがありません。
  3. ファイアウォール/パケットフィルタリングのドロップルールの一致、
  4. 宛先IPとポートをリッスンしているアプリケーションはありません。
  5. リスニングアプリケーションソケットの受信バッファがいっぱいです。

最初の2つのポイントはトラフィックが多すぎることですが、ここではそうではない可能性があります。次に、ポイント4は適用されず、ソフトウェアがデータを待機していると信じています。ポイント5は、アプリケーションがネットワークデータを十分に高速に処理していないことです。これもそうではないようです。

MACアドレスとIPアドレス間の変換は、アドレス解決プロトコルを介して行われます。ネットワークが適切に構成されている場合、これによってパケットドロップが発生することはありません。

Windowsファイアウォールとアンチウイルス/ディープパケットインスペクションソフトウェアを無効にして、wiresharkで何がネットワーク上にあるかを確認します。これにより、正しい方向を示す可能性が高くなります。「送信先」マシンで最初のパケットをスニッフィングできる場合は、ローカル構成(ファイアウォールなど)を確認してください。そうでない場合は、ネットワークを確認してください。パス内の何かがトラフィックを妨害しています。

お役に立てれば。

于 2012-08-05T00:12:36.463 に答える
1

erm.....そのコンピュータはARP要求を実行しています。最初に送信を開始したとき、comは受信者のMACアドレスを認識していないため、パケットを送信できません。受信者のIPアドレスを使用してARP要求を実行し、Macアドレスを取得します。このプロセス中、宛先MACアドレスがまだ不明であるため、送信しようとするudpパケットを送信できません。

comがMACアドレスを受信すると、送信を開始できます。ただし、MACアドレスはcomのARPキャッシュに2分間(ユーザーと受信者の間でそれ以上のアクティビティが検出されない場合)または10分間(接続がアクティブな場合でもARPキャッシュが完全にクリアされる場合)だけ残ります。そのため、数分ごとにこの問題が発生します。

于 2012-08-24T03:48:26.260 に答える
-3

誰かがその問題を知っていますか?

本当の問題は、UDPパケット送信が信頼できると仮定したことです。そうではありません。

現在のネットワーク構成で最初のパケットが失われるという事実は、実際には二次的な問題です。あなたはそれを修正することができるかもしれませんが、いつでもあなたはまだパケット損失に対して脆弱です。

パケット損失が問題になる場合は、実際にはTCPを使用する必要があります。UDPで信頼性の高いプロトコルを構築できますが、そうする非常に正当な理由がない限り、推奨されません。

于 2012-08-06T19:34:13.370 に答える