代码之家  ›  专栏  ›  技术社区  ›  ThatsRightJack

套接字地址显示0.0.0.0,导致发送消息失败

  •  0
  • ThatsRightJack  · 技术社区  · 7 年前

    我一直在Beejs网络示例中工作,介绍一些定制。特别是,我正试图使用一个单一的结构来存储与通信/套接字相关的必要信息。我想我在填充 addrinfo 结构和使用它 sendto 用于UDP套接字。下面是我的代码,它编译得很好,但是失败了,下面概述的消息

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netdb.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    
    // Definitions
    #define COM_MSG_SIZE 1024
    #define COM_HOST_SIZE 128
    
    
    struct com_socket
    {
        char *type;
        int descriptor;
        struct addrinfo addr;
    };
    
    
    void COM_error(char *msg) {
        perror(msg);
        exit(0);
    }
    
    
    int main()
    {
    
        int status;
        struct com_socket COM_client;
        char addr_str[COM_HOST_SIZE];
    
        // ---------------------------------------------
        // Initialize socket
        COM_client.type = "UDP";
        char *hostname = "192.168.0.110";
        char *port_num = "4000";
    
        printf("Creating socket...");
        if(strcmp(COM_client.type, "UDP") == 0)
        {
            COM_client.descriptor = socket(AF_INET, SOCK_DGRAM, 0);
        }
    
        // Error check
        if(COM_client.descriptor < 0)
        {
            COM_error("  ERROR opening socket");
        }
        printf("  Success\n");
    
    
        //------------------------------------------------------------------------------------------
    
        // Define hints
        struct addrinfo hints;
    
        hints.ai_family = AF_INET; // AF_UNSPEC "unspecified" or can use IPv6 = AF_INET6, IPv4 =  AF_INET
        hints.ai_socktype = SOCK_DGRAM; // Socket type: SOCK_STREAM or SOCK_DGRAM or 0 = auto
        hints.ai_flags = AI_CANONNAME;
        hints.ai_protocol = 0; // 0 = auto
        hints.ai_canonname = NULL;
        hints.ai_addr = NULL;
        hints.ai_addrlen = 0;
        hints.ai_next = NULL;
    
        // Get the linked list of address info
        struct addrinfo *host_list;
        printf("Building host address list...");
        status = getaddrinfo(hostname,port_num,&hints,&host_list);
    
        // returns 0 if succeeds
        if (status != 0)
        {
            COM_error("  ERROR getaddrinfo: %s\n");
        }
        printf("  Success\n");
    
    
        //------------------------------------------------------------------------------------------
        // Select address
    
        int count = 1;
        struct addrinfo *entry;
    
        // Loop through each entry in the "linked list" and pull the necessary one
        for (entry = host_list; entry != NULL; entry = entry->ai_next)
        {
    
            // Print the list of potential IP addresses
            if( NULL == inet_ntop( AF_INET, &((struct sockaddr_in *) entry->ai_addr)->sin_addr, addr_str, sizeof(addr_str) ) )
            {
                COM_error("  ERROR with inet_ntop\n");
            }
            printf("  Address entry %d: %s",count,addr_str);
    
            // Update counter
            count = count + 1;
    
            // Choose which one to copy
            if(strncmp(addr_str,"192.",(size_t) 4) == 0)
            {
    
                //memcpy(COM_client.addr,entry, sizeof(struct addrinfo));
                COM_client.addr = *entry;
    //          COM_client.addr.ai_addr = entry->ai_addr;
    //          COM_client.addr.ai_addrlen = entry->ai_addrlen;
    //          COM_client.addr.ai_canonname = entry->ai_canonname;
    //          COM_client.addr.ai_family = entry->ai_family;
    //          COM_client.addr.ai_flags = entry->ai_flags;
    //          COM_client.addr.ai_protocol = entry->ai_protocol;
    //          COM_client.addr.ai_socktype = entry->ai_socktype;
    
                if( inet_ntop( AF_INET, &((struct sockaddr_in *) COM_client.addr.ai_addr)->sin_addr, addr_str, sizeof(addr_str) ) == NULL )
                {
                    COM_error("  ERROR with arguments to inet_ntop\n");
                }
    
                printf("   <--------- selected* (%s) \n",addr_str);
                break;
            }
            else
            {
                printf("\n");
            }
        }
    
        // Clean
        freeaddrinfo(host_list);
    
    
        //-------------------------------------------------------
    
    
        char *buffer;
        char msg[COM_MSG_SIZE];
        strncpy(msg,"BEGIN",COM_MSG_SIZE);
    
    
        printf("ENTER `COM_msg_send` address length %d\n",COM_client.addr.ai_addrlen);
    
        buffer = calloc(COM_MSG_SIZE+1, sizeof(char));
    
        printf("AFTER calloc `COM_msg_send` address length %d\n",COM_client.addr.ai_addrlen);
    
        // Check to see if we were successful
        if (buffer == NULL)
        {
            printf("ERROR Could not allocate required memory\n");
            exit(1);
        }
    
        // Copy message to buffer
        strncpy(buffer,msg,COM_MSG_SIZE);
        printf("Message input: %s   Message to be sent: %s\n",msg,buffer);
    
    
        if( inet_ntop( AF_INET, &((struct sockaddr_in *) COM_client.addr.ai_addr)->sin_addr, addr_str, sizeof(addr_str) ) == NULL )
        {
            COM_error("  ERROR with arguments to inet_ntop\n");
        }
        printf("SEND to address (%s) \n",addr_str);
    
    
        // Send the buffer to the destination address
        if(strcmp(COM_client.type, "UDP") == 0)
        {
            status = sendto(COM_client.descriptor, buffer, strlen(buffer), 0, COM_client.addr.ai_addr, COM_client.addr.ai_addrlen);
    
            // Error check
            if (status < 0)
            {
                COM_error("ERROR could not send message");
            }
    
        }
    
        // Free buffer memory
        free(buffer);
    
        //---------------------------------------------------------
        close(COM_client.descriptor);
    
        return 0;
    }
    

    这是显示打印语句消息以及失败的输出

    Creating socket...  Success
    Building host address list...  Success
      Address entry 1: 192.168.0.110   <--------- selected* (192.168.0.110) 
    ENTER `COM_msg_send` address length 16
    AFTER calloc `COM_msg_send` address length 16
    Message input: BEGIN   Message to be sent: BEGIN
    L1 = 16  L2 = 16 
    SEND to address (0.0.0.0) 
    ERROR could not send message: Invalid argument
    

    显示 SEND to address (0.0.0.0) ,似乎存储在结构COM客户机中的地址有问题。具体来说,我认为我在这方面有困难

                //memcpy(COM_client.addr,entry, sizeof(struct addrinfo));
                COM_client.addr = *entry;
    //          COM_client.addr.ai_addr = entry->ai_addr;
    //          COM_client.addr.ai_addrlen = entry->ai_addrlen;
    //          COM_client.addr.ai_canonname = entry->ai_canonname;
    //          COM_client.addr.ai_family = entry->ai_family;
    //          COM_client.addr.ai_flags = entry->ai_flags;
    //          COM_client.addr.ai_protocol = entry->ai_protocol;
    //          COM_client.addr.ai_socktype = entry->ai_socktype;    
    

    如你所见,我尝试过各种方法,但都失败了。我想继续使用 COM_client 结构方法,因为我的意图是使代码更模块化,在其中我可以传递包含所有必要的通信信息的结构。

    1 回复  |  直到 7 年前
        1
  •  0
  •   alk    7 年前

    这条线

    COM_client.addr = *entry;
    

    “尝试”复制 struct addrinfo 它实际上是这样做的,但是因为它包含指针并且“仅”复制指针的值。那些指针指向的内存已由分配 getaddrinfo() 因此将通过调用 freeaddrinfo() 将指针留在副本中,然后悬空。

    要解决这个问题,您需要执行 结构addrinfo .

    例如,可以这样做:

    /* Does a deep copy to where pdst point from where pscr points to. 
       Returns 0 on success and -1 on error. Sets errno. */   
    
    int addrinfo_copy(struct addrinfo * pdst, struct addrinfo * psrc)
    {
      int result = 0; /* Be optimistic. */
    
      assert(pdst);
      assert(psrc);
    
      *pdst = *pscr; /* Copy all. Note that the pointer elements copied
                       need to be recreated. See below ... */
      do
      {
        pdst->ai_addr = malloc(psrc->ai_addrlen);
        if (!pdst->ai_addr)
        {
          result = -1;
          break;
        }
    
        memcpy(pdst->ai_addr, psrc->ai_addr, psrc->ai_addrlen);
    
        pdst->ai_canonname = strdup(psrc->ai_canonname); /* Assumes POSIX. */
        if (!pdst->ai_canonname)
        {
          result = -1;
          break;
        }
      } while (0);
    
      return result;       
    }
    

    要删除这样的副本,您需要这样做:

    /* Deallocates and sets to a 0/NULL what had been created by 
       addrinfo_copy(). */
    
    void addrinfo_free(struct addrinfo * p)
    {
      assert(p);
    
      free(p->ai_addr);
      free(p->canonname);
    
      memset(p, 0, sizeof *p); /* In fact not necessary. */
    }
    

    这样使用:

      struct addrinfo * entry, * entry_copy;
    
      /* Set entry to something returned by getaddrinfo (). */
      ...
    
      if (-1 = addrinfo_copy(entry_copy, entry))
      {
        perror("addrinfo_copy() failed"):
        exit(EXIT_FAILURE);
      }
    
      /* Deallocate all results returned by getaddrinfo(). */
      freeaddrinfo(...);
    
      /* Still use entry_copy here. */
      ...
    
      /* Clean up. */
      addrinfo_free(entry_copy);
    

    最后请注意:

    如果在进行C时,你发现内存内容发生了模糊的突然/意外的变化,这一切都是因为写和/或读到“错误”的内存而破坏了内存管理。在记忆中的那些变化变得明显和/或代码中的那些变化(表面上)与你在哪里观察到的记忆中的这些变化完全无关之前,有些时候会发生这种情况。