2

UDPを使用して単純なWebサーバーとクライアントを作成していますが、これまでのところ:

  • プログラムは相互に接続でき、
  • クライアントはリクエストを送信できます。
  • サーバーはリクエストを読み取ることができ、
  • サーバーはクライアントの IP アドレスとクライアントのポートを認識できます。
  • サーバーはメッセージをクライアントに送り返すことができます

私の問題はrcvfrom、サーバーが応答を送信した後でも、クライアント コードが関数内で待機状態になることです。

以下は、サーバー メッセージを取得し、ソケットによって読み取られたバイト数を返す関数です。

ssize_t receive_from_server(rdp_socket *rsocket, char *buffer, size_t buf_len){

  socklen_t sendsize = sizeof(rsocket->server_addr);
  bzero(&(rsocket->server_addr), sendsize);
  //STUCK HERE:
  return recvfrom(rsocket->sockfd, buffer, buf_len, 0,           
       (struct sockaddr*)&(rsocket->server_addr), &sendsize);
}

SO_SNDTIMEO両方のソケットオプトを設定しSO_RCVTIMEO、数秒後にタイムアウトするようにしました。

質問:

近い将来、信頼できるデータ転送のために確認応答 (ACK) を追加する予定です。ACKの欠落が問題になる可能性があると思いますが、訓練された目で見ると、別の問題のように見えるのではないかと思っています.

タイムアウトが機能するためには ACK が必要ですか?

クライアントとサーバーが実際に相互に通信できるように同期するにはどうすればよいですか?

4

1 に答える 1

2

UDP は信頼性を提供しないため、失われたデータの再送信を実装する必要があります。これはクライアント リクエスト サーバー レスポンス モデルのように見えるため、最も簡単な再送信の実装は、レスポンス待ちのタイムアウト時にリクエストを再送信し、再度レスポンスを待つことです。再試行カウンターを実装し、特定の回数の再試行後にあきらめることができます。

SO_RCVTIMEOおよびSO_SNDTIMEOソケット オプションが効果を発揮していないように見える場合は、それらのオプションがそのタイプのソケットに実装されていない可能性があります。呼び出しの戻り値をチェックしてsetsockopt()、成功したことを確認します。

回避策として、でブロックする代わりに、読み取り可能なイベントを使用するか、ある程度の時間待機するようにreceive_from_server()関数を変更できます。poll()select()recvfrom()

ssize_t receive_from_server(rdp_socket *rsocket, char *buffer, size_t buf_len){
  struct pollfd pfd = { rsocket->sockfd, POLLIN };
  int pollresult = poll(&pfd, 1, RECV_TIMEOUT_SECONDS * 1000);

  if (pollresult > 0) {
    socklen_t sendsize = sizeof(rsocket->server_addr);
    bzero(&(rsocket->server_addr), sendsize);

    return recvfrom(rsocket->sockfd, buffer, buf_len, MSG_DONTWAIT,           
      (struct sockaddr*)&(rsocket->server_addr), &sendsize);
  }

  if (pollresult == 0) {
      errno = ETIME;
  }

  return -1;
}
于 2013-07-31T19:04:35.647 に答える