sockets - UDP Talker在sendto()调用中给出 “Bad value for ai_flags”

标签 sockets udp sendto

我对UDP对话者应用程序感到困惑。
目前的目标是初始化服务器,注册一个客户端,然后继续向该客户端发送消息。
我已经按照Beej的网络指南进行工作,并对以下库实现进行了编码:

这使服务器变得井井有条

int init_udp_server(const char *port_string){

  /** Check the input data **/
  if(port_string == NULL)
    port_string = DEFAULT_PORT;

  /** Get the information for the server **/
  memset(&addrinfo_hints, 0, sizeof addrinfo_hints);
  /* Use either protocol (v4, v6) */
  addrinfo_hints.ai_family = AF_UNSPEC;
  /* Use UDP socket type */
  addrinfo_hints.ai_socktype = SOCK_DGRAM;
  /* Use system IP */
  addrinfo_hints.ai_flags = AI_PASSIVE;

  if( (ret = getaddrinfo(NULL, port_string, &addrinfo_hints, &addrinfo_server)) 
      != 0 ){
    printf("Server:getaddrinfo: %s\n", gai_strerror(ret));  
    return -1;
  }

  /** Loop through the list returned by getaddrinfo and get socket **/
  for( addrinfo_queue = addrinfo_server; addrinfo_queue != NULL; 
      addrinfo_queue = addrinfo_queue->ai_next){
    if((sockfd = socket(addrinfo_queue->ai_family,
            addrinfo_queue->ai_socktype, addrinfo_queue->ai_protocol)) == -1){
      error("Server: get socket failed");
      continue;
    }
    if(bind(sockfd, addrinfo_queue->ai_addr, addrinfo_queue->ai_addrlen)
        == -1){
      close(sockfd);
      error("Server: Bind to socket error");
      continue;
    }
    break;

  }
  /* If we got to addrinfo_queue == NULL, we did not get a valid socket */
  if(addrinfo_queue == NULL){
    error("Server: Could not bind a socket");
    return -1;
  }
  /* We do not need the addrinfo_server anymore */
  freeaddrinfo(addrinfo_server);
  return 0;
}

这注册了客户端
int udp_server_setup_client(const char *client_addr, const char *port_string, int     client_nr){


  /** Check the input data **/
  if(port_string == NULL)
    port_string = DEFAULT_PORT;
  if(client_addr == NULL){
    error("No valid client list");
    return -1;
  }
  if(client_nr < 0 || client_nr > 7){
    error("No valid client Nr.");
    return -1;
  } 

  memset(&addrinfo_hints, 0, sizeof addrinfo_hints);
  /* Use either protocol (v4, v6) */
  addrinfo_hints.ai_family = AF_UNSPEC;
  /* Use UDP socket type */
  addrinfo_hints.ai_socktype = SOCK_DGRAM;

  /* Get the information for the client */
  if( (ret = getaddrinfo( client_addr, port_string, &addrinfo_hints,
          &current)) != 0 ){
    printf("Client:getaddrinfo: %s\n", gai_strerror(ret));  
    return -1;
  }
  else{
    /* We read out the IP, kind of a nice check to see wheter all went fine */
    char ip4[INET_ADDRSTRLEN];
    struct sockaddr_in *sa = (struct sockaddr_in*) current->ai_addr;
    inet_ntop(AF_INET, &(sa->sin_addr),ip4, INET_ADDRSTRLEN);
    printf("Clients address: %s\n",ip4);
    addrinfo_clients[client_nr] = current;
  }
  return 0;
}

最后这是为了写作
int udp_server_write(const char *buffer, int buffer_size, int client_nr){
  /* Sanity check of the input */
  if(client_nr > (MAX_NR_CLIENTS - 1) || client_nr < 0){
    error("Not a valid client");
    return -1;
  }
  if(buffer == NULL){
    error("Not a valid buffer address");
    return -1;
  }
  /* Just so we type less */
  current = addrinfo_clients[client_nr];

  socklen = sizeof current->ai_addr; 
  if((ret = sendto(sockfd, (void*)buffer, buffer_size, 0,
        (sockaddr*)current->ai_addr, socklen)) == -1){
    printf("Failed to send message to client %i\n", client_nr);
    printf("Error Code: %s\n",gai_strerror(ret)); 
    return -1;    
    }
  else if(ret < buffer_size){
    printf("Wrote only %i of %i bytes\n", ret, buffer_size);
    return -1;
  }
  return ret;
}

我称这样的功能
init_udp_server("3334"); 

udp_server_setup_client("192.168.1.5", "3334", 0);

udp_server_write(send_buf, 256, 0);

一旦调用sendto(),我就会收到一个错误:
无法向客户端0发送消息
错误代码:ai_flags值错误
我用gdb进行了检查,发现addrinfo结构正确填充,并且客户端的地址有效。
有人知道在哪里看吗?我的想法不多了...

谢谢,温茨尔恩

最佳答案

调用sendto()时,最后一个参数被设置为sizeof current->ai_addr,这是错误的。 current->ai_addr定义为sockaddr*指针,因此sizeof current->ai_addr在32位系统上始终返回4,在64位系统上返回8。碰巧IPv4地址的大小为4个字节,因此sizeof current->ai_addr仅适用于32位系统上的IPv4地址,但对于32位系统上的IPv6地址和64位系统上的所有地址始终无效。您需要使用current->ai_addrlen而不是sizeof

同样,将-1传递给gai_strerror()也是无效的。它期望您传递真实的错误代码,例如getaddrinfo()getnameinfo()的返回值。 sendto()不返回实际的错误代码。如果失败,则必须在Windows上使用WSAGetLastError()或在其他系统上使用errno来获取实际的错误代码。

试试这个:

if ((ret = sendto(sockfd, (char*)buffer, buffer_size, 0, (sockaddr*)current->ai_addr, current->ai_addrlen)) == -1)
{
    #ifdef _WIN32
    ret = WSAGetLastError();
    #else
    ret = errno;
    #endif

    printf("Failed to send message to client %i\n", client_nr);
    printf("Error Code: (%d) %s\n", ret, gai_strerror(ret)); 
    return -1;    
}

关于sockets - UDP Talker在sendto()调用中给出 “Bad value for ai_flags”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14125750/

相关文章:

Java:将数据从一个线程传送到另一个线程

iPhone - gcdasyncsocket 委托(delegate) Didreceive 在其他 View 中不起作用

Python - sendto() 的返回值没用吗?

java - 通过服务器自动化 Web 浏览器

windows - 如何更改程序的套接字绑定(bind)端口?没有源代码

windows - recv() 没有时间从 Win 7 上的套接字接收所有 UDP 数据包?

c - 套接字 - C 中的权限被拒绝

c - 两种方式的 UDP 客户端和服务器?

java - 如何连接到本地IP地址

c++ - 在哪种情况下 UDP 套接字上的 sendto() 返回 0?