0

概要

comp.sci 用に Linux 上の C 言語で HTTP over UDP を使用して通信するクライアント サーバー アプリケーションを作成します。大学プロジェクト。

ネットワークのセットアップには注意が必要です。クライアントとサーバーの両方でローカル IP アドレスをバインドする必要があります。クライアントが IP アドレスをバインドしようとすると、サーバーはクライアントの IP アドレスを特定できますが、パケットを受信できません。クライアントがバインドを実行しない場合、クライアントとサーバーはほぼ問題なく通信しますが、サーバーはクライアントの IP アドレスを判別できません。

クライアント + サーバー コード

バインディング用のクライアント コードは次のとおりです。

*編集: 提案されているように、関数呼び出しの下で perror を上に移動しました *

   if (bind(client_socket.sockfd, (struct sockaddr *) &(client_socket.client_addr), 
      sizeof(client_socket.client_addr)) < 0){
    perror("error on binding!"); 
    debug(("client: bind"),__LINE__, __FILE__);
    close(client_socket.sockfd);
    return -1;
  }

ソケットを開くためのクライアントとサーバーのコードは次のとおりです。

int RDP_getSock(char *server_addr, char *server_port, rdp_socket *rsocket){
  rsocket->sockfd = socket(AF_INET, SOCK_DGRAM, 0);

  if(rsocket->sockfd <0 ){
    return -1;
  }

  bzero(&(rsocket->server_addr),sizeof(rsocket->server_addr));
  rsocket->server_addr.sin_family = AF_INET;
  rsocket->server_addr.sin_port = htons(atoi(server_port));

  if(server_addr != NULL){
    rsocket->server_addr.sin_addr.s_addr = inet_addr(server_addr);

    if( rsocket->server_addr.sin_addr.s_addr <0 ){
      return -1;
    }

  }

  rsocket->connected = 0;
  return 0;
}

クライアントはそれを呼び出します:

  if(RDP_getSock(argv[3], argv[4], &client_socket) <0 ){
        perror("client: error on RDP_getSock()");
        return -1;
    }

サーバーはそれを呼び出します:

  if(RDP_getSock( NULL, argv[2], &server_socket) == -1 ){
        perror("server: error on RDP_getSock()");
        return -1;
    }  

クライアントがサーバーに送信しようとすると、次のエラー メッセージが表示されます。

receive ACK error: Resource temporarily unavailable
EAGAIN error
: Resource temporarily unavailable

サーバーから読み取るコード (クライアントから読み取るコードと同様):

ssize_t RDP_receive_from_server(rdp_socket *rsocket, rdp_packet *packet){
  socklen_t address_length = sizeof( struct sockaddr_in );
  bzero(&(rsocket->server_addr), address_length);
  bzero(packet->header.type, RDP_HEADER_TYPE_SIZE);


  return recvfrom(rsocket->sockfd, packet, MAX_PACKET_SIZE, 0, (struct sockaddr*)&(rsocket->server_addr), &address_length);
}

クライアントとサーバーの両方にタイムアウトが設定されています。しかし、クライアントとサーバーは技術的には同じマシン上にあるため、クライアントを強制的にローカル IP アドレスにバインドすると失敗する理由がわかりません。

実際にパケットを (クライアント/サーバーとの間で) 送信するコード:

ssize_t RDP_send_packet(rdp_socket *rsocket, rdp_packet *packet, int to_client){
  ssize_t result = -1;
  socklen_t address_length = sizeof( struct sockaddr_in );
  char src_ip[256];
  char dest_ip[256];
  bzero(src_ip, 256);
  bzero(dest_ip,256);

  if(to_client){
    debug(("send to client"),__LINE__, __FILE__);
    result = sendto(rsocket->sockfd, packet, sizeof(struct RDP_packet), 0,
        (struct sockaddr *)&(rsocket->client_addr),sizeof(rsocket->client_addr));

    // inet_ntoa(rsocket.client_addr.sin_addr), ntohs(server_socket.client_addr.sin_port));

    strncpy(src_ip, inet_ntoa(rsocket->server_addr.sin_addr), 256);
    debug(src_ip,__LINE__, __FILE__);

    strncpy(dest_ip, inet_ntoa(rsocket->client_addr.sin_addr), 256);
    debug(dest_ip,__LINE__, __FILE__);

    RDP_logline(
      's',
      src_ip,
      ntohs(rsocket->server_addr.sin_port),
      dest_ip,
      ntohs(rsocket->client_addr.sin_port),
      packet->header.type,
      packet->header.seq );     
  }
  else{
    debug(("send to server"),__LINE__, __FILE__);
    result = sendto(rsocket->sockfd, packet, sizeof(struct RDP_packet), 0,
        (struct sockaddr *)&(rsocket->server_addr),sizeof(rsocket->server_addr));  

    strncpy(src_ip, inet_ntoa(rsocket->client_addr.sin_addr), 256);
    debug(src_ip,__LINE__, __FILE__);

    strncpy(dest_ip, inet_ntoa(rsocket->server_addr.sin_addr), 256);
    debug(dest_ip,__LINE__, __FILE__);

    RDP_logline(
      's',
      src_ip,
      ntohs(rsocket->client_addr.sin_port),
      dest_ip,
      ntohs(rsocket->server_addr.sin_port),
      packet->header.type,
      packet->header.seq );        
  }

  debug(("send complete"),__LINE__, __FILE__);
  return result;
}

IP アドレスを示すロギング

クライアントからのログ行を次に示します。クライアント IP/ポートとサーバー IP/ポートが示され、クライアントにバインドされています (IP アドレス 192.168.1.100 が予期される値です)。

2013-08-06 18:47:27.433176 s 192.168.1.100:8080 10.10.1.100:9090 SYN 1

サーバー側から:

2013-08-06 18:52:30.321409 s 0.0.0.0:9090 0.0.0.0:0 ACK 1

クライアントからのログ行。クライアント IP/ポートとサーバー IP/ポートが示され、バインディングはありません。

2013-08-06 19:22:17.613885 s 176.39.64.0:0 10.10.1.100:9090 ACK 2

サーバーから:

2013-08-06 19:22:17.613858 s 0.0.0.0:9090 10.10.1.100:37887 FIN 2

クライアント側でバインドが使用されていない場合、クライアントに割り当てられているように見える IP アドレスとポートはランダムです (例: 176.39.64.0:0)。

質問

クライアントでバインドすると、サーバーが ACK パケットを送り返すのを妨げている理由はありますか?

4

0 に答える 0