5

バッファサイズに達するまで、バイト配列をX回送信したいと思います。私のクライアントは、バッファサイズがいっぱいになるまでバイト配列を送信します。しかし、問題はパケット損失であり、サーバーはバッファサイズの8/10程度しか受信しません。

クライアント:

while(writeSize < bufferSize)
{
    bytes_sent += sendto(servSocket, package, sizeof(package), 0, (struct sockaddr *)&server, sizeof(server));
    writeSize+= sizeof(package);    
}

サーバ:

while(packetSize < bufferSize)
{
    bytes_recv += recvfrom(servSocket, package, sizeof(package), 0, (struct sockaddr*)&client, &size);
    packetSize += sizeof(package);
    printf("Bytes recieved: %d\n", bytes_recv);
}

私はこの問題の解決策を本当に思いつくことはできません。クライアントがすべてのパッケージを送信し、サーバーがパッケージの損失に苦しんでいるときにwhileループが終了しない場合、これを解決する方法はありますか?

どうもありがとう

4

4 に答える 4

2

Hmpf。UDPを使用しています。このプロトコルでは、必要に応じてパケットを破棄してもまったく問題ありません。そのため、「送信されたものが到着する」という点では信頼できません。クライアントで行う必要があるのは、必要なすべてのパケットが到着したかどうかを確認し、到着していない場合は、サーバーに丁寧に話しかけて、受信しなかったパケットを再送信することです。このようなものを実装するのはそれほど簡単ではなく、最終的には、単純な古いtcpソケットを使用するよりもパフォーマンスが低下する可能性があるソリューションになってしまう可能性があるため、最初にtcp接続に切り替えることをお勧めします。

于 2013-01-18T12:37:21.023 に答える
2

大量のデータを転送するためにUDPを使用する必要がある場合は、パケット損失と並べ替えの可能性を処理する小さなアプリケーションレベルのプロトコルを設計します(これはTCPが行うことの一部です)。私はこのようなもので行きます:

  • IPフラグメンテーションを回避するためのサイズ(たとえば1024バイト)のデータグラムがMTU(およびIPヘッダーとUDPヘッダー)よりも小さい
  • データ長シーケンス番号を含む各データグラムの固定長ヘッダー。これにより、データをつなぎ合わせて、欠落、重複、および並べ替えられたパーツを検出できます。
  • 正常に受信され、まとめられたものの受信側からの謝辞。
  • これらのackが適切な時間内に来ない場合の送信側でのタイムアウト再送信。

どうぞ。TCPの構築を再開しました...

于 2013-01-18T16:54:44.087 に答える
0

もちろんTCPの方が適していますが、UDPオプションしかない場合は、データをシーケンスとbuf_lengthフィールドを持つ構造にラップします。

これは絶対に最適なソリューションではありません...データが完全に正しい順序で到着することを保証するために、シーケンス番号を処理するだけです。そうでない場合は、データの受信を停止します(順序が間違っていても、送信を依頼してピースを再送信し、データを再構築するなど、よりスマートな方法を実行できますが、非常に複雑になります)

struct udp_pkt_s {
    int     seq;
    size_t  buf_len;
    char    buf[BUFSIZE];
};

送信側:

struct udp_pkt_s udp_pkt;

udp_pkt.seq = 0;

while(writeSize < bufferSize)
{
    // switch to the next package block
    // ...

    memcpy(udp_pkt.buf, package);
    udp_pkt.buf_len = sizeof(package);
    udp_pkt.seq++;

    bytes_sent += sendto(servSocket, &udp_pkt, sizeof(udp_pkt_s), 0, (struct sockaddr *)&server, sizeof(server));
    writeSize += sizeof(package);    
}

受信側:

last_seq = 0;

while(packetSize < bufferSize)
{
    bytes_recv += recvfrom(servSocket, &udp_pkt, sizeof(udp_pkt_s), 0, (struct sockaddr*)&client, &size);

    // break it if there's a hole
    if (udp_pkt.seq != (last_seq + 1))
        break;

    last_seq = udp_pkt.seq;

    packetSize += udp_pkt.buf_len;

    printf("Bytes recieved: %d\n", udp_pkt.buf_len);
}
于 2013-01-18T15:30:01.043 に答える
0

sendtoの後、sendtoバッファーがゼロに達するのを待つことができます。その後、各sendto呼び出しの後に次のAPIを使用できます。

void waitForSendBuffer(void)
{
int outstanding = 0;
while(1)
{
  ioctl(socketFd_, SIOCOUTQ, &outstanding);
  if(outstanding == 0)
    break;
  printf("going for sleep\n");
  usleep(1000);
}
}
于 2014-02-19T08:50:08.197 に答える