0

概述

在 Linux 上使用 C 中的 HTTP over UDP 为 comp.sci 编写客户端-服务器应用程序进行通信。大学项目。

网络设置很棘手:客户端和服务器都需要绑定本地 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