【问题标题】:Why inet_ntop() and inet_ntoa() gives different result?为什么 inet_ntop() 和 inet_ntoa() 给出不同的结果?
【发布时间】:2017-10-11 03:08:16
【问题描述】:

我正在创建一个 UDP 服务器-客户端程序。客户端请求一个文件,如果找到,服务器将发送给客户端。 基于 Beej 的网络指南,

  • inet_ntoa() 返回静态缓冲区中的点和数字字符串,每次调用函数都会覆盖该缓冲区。
  • inet_ntop() 成功时返回 dst 参数,失败时返回 NULL(并且设置了 errno)。

该指南提到不推荐使用 ntoa,因此建议使用 ntop,因为它支持 IPv4 和 IPv6。

在我的代码中,当我使用函数或其他函数时,我得到了不同的结果,我的理解是它们应该抛出相同的结果。有什么我想念的吗?任何帮助将不胜感激。

代码:

    //UDP Client
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>

    #define MAXBUFLEN 1024
    #define SER_IP "176.180.226.0" 
    #define SER_PORT "1212"

    // Get port, IPv4 or IPv6:
    in_port_t get_in_port(struct sockaddr *sa){
        if (sa->sa_family == AF_INET) {
            return (((struct sockaddr_in*)sa)->sin_port);
        }
        return (((struct sockaddr_in6*)sa)->sin6_port);
    }

    int main(int argc, char *argv[]){
        int sock, rv, numbytes;
        struct addrinfo hints, *servinfo, *p;
        char buffer[MAXBUFLEN];

        memset(&hints, 0, sizeof hints);
        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_DGRAM;

        rv = getaddrinfo(NULL, SER_PORT, &hints, &servinfo);
        if (rv != 0){
            fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
            exit(1);
        }

        // Printing IP, should provide same result
        for(p = servinfo; p != NULL; p = p->ai_next) {
            char str1[INET_ADDRSTRLEN];
            inet_ntop(AF_INET, &p->ai_addr, str1, INET_ADDRSTRLEN); 
            printf("ntop:%s\n", str1) ;
            printf("inet_ntoa:%s \n", inet_ntoa(((struct sockaddr_in *)p->ai_addr)->sin_addr));
            printf("\n");
        }

        exit(1);
    }

当前输出:

ntop:64.80.142.0
inet_ntoa:0.0.0.0 

ntop:160.80.142.0
inet_ntoa:127.0.0.1 

【问题讨论】:

    标签: c networking


    【解决方案1】:

    根据man 页面,对于AF_INET,参数src 必须指向struct in_addr(网络字节顺序)。

    在你的struct addrinfo 中有一个指向struct sockaddr 的指针,基本上是

    sa_family_t sa_family;
    char        sa_data[];
    

    但是,struct sockaddr_in

    sa_family_t    sin_family;
    in_port_t      sin_port;
    struct in_addr sin_addr;
    

    所以,你需要更换

    inet_ntop(AF_INET, &p->ai_addr, str1, INET_ADDRSTRLEN);
    

    任一个

    inet_ntop(AF_INET, &p->ai_addr->sa_data[2], str1, INET_ADDRSTRLEN);
    

    src 参数可能是&amp;p-&gt;ai_addr-&gt;sa_data[1 &lt;&lt; 1] 以避免“幻数”2 - 端口号存储的偏移量)

    inet_ntop(AF_INET, &((struct sockaddr_in *)p->ai_addr)->sin_addr, str1, INET_ADDRSTRLEN);
    

    然后它将产生正确的输出。

    【讨论】:

    • 我相信避免幻数的“正确”(POSIX)方法是使用offsetof(struct sockaddr_in, sin_addr) - offsetof(struct sockaddr, sa_data)之类的东西来计算它,因为绝对不能保证这些结构只有这些成员或者它们是按此(或任何)特定顺序排列。
    猜你喜欢
    • 2017-04-29
    • 2021-12-07
    • 2020-10-15
    • 1970-01-01
    • 1970-01-01
    • 2010-10-29
    • 1970-01-01
    • 1970-01-01
    • 2021-03-14
    相关资源
    最近更新 更多