概要
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 パケットを送り返すのを妨げている理由はありますか?