8

UDP を使用する信頼性の高いファイル転送プログラムに取り組んでいます。(コンピュータ ネットワーキングのコースの場合。)

私の質問はこれです-まあ、このシナリオを考えてください:

  1. 送信者には、(たとえば) 送信する 12 バイトのデータがあります。したがって、送信者は次の呼び出しを実行します。

    sendto(fd, &buf, 12, 0, (struct sockaddr *)&cliaddr,sizeof(cliaddr));
    

    これにより、信頼できない方法で 12 バイトのデータが送信されます。このデータの最初の 4 バイトはたまたま「メッセージ長」フィールドです。この場合、最初の 4 バイトの値は 0x0000000C になる可能性があります。

  2. 受信者は、recvfrom() を使用して最初の 4 バイトを読み取りたいと考えています。セグメント サイズが 12 バイトであることを確認して、残りの 8 バイトを読み取ります。したがって、レシーバーは次のようになります。

    /* read the segment size */
    recvfrom(sockfd,&buf,4,0,(struct sockaddr *)&cliaddr,&len);
    
    /* do some arithmetic, use bzero(), etc */
    
    /* read the rest of the data */
    recvfrom(sockfd,&buf,8,0,(struct sockaddr *)&cliaddr,&len);
    

このコードを実行すると、最初の 4 バイトは問題なく受信できます。しかし、残りのデータを取得しようとすると、そのデータが失われたようです。私の出力では、ガベージが表示されています。次の12 バイトの一部のように見えますが、送信者は sendto() を行っています。

これは予想される動作ですか?つまり、1 回の recvfrom() 呼び出しで送信されたすべてのデータを読み取れない場合、そのデータ (残りの 8 バイト) が利用可能であるという保証はありませんか?

セグメント ヘッダー (サイズを含む) を送信し、その後にペイロードを送信する標準的な方法は機能しないようです。これは、ヘッダー情報のみを含む 2 つのセグメントと、ペイロードを含む 2 番目のセグメントを送信する必要があるということですか? それとも、これらのシステムコールを間違って使用しているだけですか (または、欠落しているフラグまたは setsockopt() がありますか?)

4

2 に答える 2

9

recv(2) の man ページから:

メッセージが長すぎて提供されたバッファに収まらない場合、メッセージの受信元のソケットのタイプによっては、余分なバイトが破棄される場合があります。

これがあなたに起こっているように見えるものです。

最大メッセージ サイズのバッファーがあり、その量を読み取る必要があります。データグラムを 1 つだけ読み取り、長さが返されます。次に、バッファーの先頭からの長さを解析し、recvfrom(2) が返したものに対して検証できます。

于 2009-03-24T01:07:37.787 に答える
2

もう 1 つの方法は、MSG_PEEK フラグを使用してダミーの recvfrom を実行することです。返されたサイズがバッファー サイズと同じ (またはそれ以上) である場合は、より大きなバッファーを取得して再試行してください。次に、(MSG_PEEK フラグを指定せずに) recvfrom を再度実行して、UDP バッファーからメッセージを削除します。

しかしもちろん、これはかなり非効率的であり、最大パケット サイズを決定できる場合には実行しないでください。

于 2009-11-10T18:32:59.437 に答える