C语言 如何从 getaddrinfo() 打印 IP 地址

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20115295/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 10:22:22  来源:igfitidea点击:

How to print IP address from getaddrinfo()

csockets

提问by user1345414

I'm trying to use socket in C on CentOS 6.4.

我正在尝试在 CentOS 6.4 上使用 C 中的套接字。

Following LIST1 is my code.

下面的 LIST1 是我的代码。

My code gets hostname from command line and sends datagram to server with UDP successfully.

我的代码从命令行获取主机名并使用 UDP 成功将数据报发送到服务器。

What I want to know is how to print IP address that getaddrinfo()resolved wiht 192.168.10.1format.

我想知道的是如何打印用格式getaddrinfo()解析的IP地址192.168.10.1

When I try to print IP address segmentation error happens.

当我尝试打印 IP 地址分段错误时发生。

Does anyone know how to fix this code?

有谁知道如何修复此代码?

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>

int
main(int argc,char *argv[]){
    int sock;
    struct addrinfo hints,*res;
    int n;
    int err;
    if(argc != 2){
        fprintf(stderr,"Usage : %s dst \n",argv[0]);
        return 1;
    } 
    memset(&hints,0,sizeof(hints));
    hints.ai_family = AF_UNSPEC; 
    hints.ai_socktype = SOCK_DGRAM;
    err = getaddrinfo(argv[1],"12345",&hints,&res);
    if(err != 0){
        perror("getaddrinfo");
        printf("getaddrinfo %s\n",strerror(errno));
        printf("getaddrinfo : %s \n",gai_strerror(err));
        return 1;
    }

    sock = socket(res->ai_family,res->ai_socktype,0);
    if(sock < 0){
        perror("socket");
        return 1;

        const char *ipverstr;
        switch (res->ai_family){
            case AF_INET:
                ipverstr = "IPv4";
                break;
            case AF_INET6:
                ipverstr = "IPv6";
                break;
            default:
                ipverstr = "unknown";
                break;            
        }
        printf("ipverstr = %s\n ",ipverstr);            
    }
    n = sendto(sock,"HELLO",5,0,res->ai_addr,res->ai_addrlen);
    if(n<1){
        perror("sendto");
        return 1;
    }
    struct sockaddr_in *addr;
    addr = (struct sockaddr_in *)res->ai_addr; 
    printf("inet_ntoa(in_addr)sin = %s\n",inet_ntoa((struct in_addr)addr->sin_addr));

    printf("############ finish !! #######\n");
    close(sock);
    freeaddrinfo(res);
    return 0;
}

回答by alk

The code misses to include the prototype for inet_ntoa().

代码没有包含inet_ntoa().

The compiler should have told you this.

编译器应该告诉你这一点。

Do add:

添加:

#include <arpa/inet.h>

However the code still compiles as due to the missing protoype for inet_ntoa()it is assumed to return int, whereas it returns a char*which is a pointer, which on a 64bit system is 8 bytes, which is not the same size as intwhich typically has a size of 4. Due to this mismatch things go terribly wrong and end up in a segmentation violation.

然而,由于缺少原型,代码仍然可以编译,因为inet_ntoa()它被假定为 return int,而它返回char*一个指针,它在 64 位系统上是 8 个字节,它的大小与int通常具有4. 由于这种不匹配,事情会变得非常错误并最终导致分段违规。



Also please note: inet_ntoa()is to be used for ipv4 addresses only. Verbatim from man inet_ntoa(italics by me):

另请注意:inet_ntoa()仅用于 ipv4 地址。逐字来自man inet_ntoa(我用斜体):

The inet_ntoa()function converts the Internet host address in, given in network byte order, to a string in IPv4dotted-decimal notation. The string is returned in a statically allocated buffer, which subsequent calls will overwrite

INET_NTOA()函数将在,互联网主机地址在网络字节顺序给出,在一个字符串的IPv4点分十进制格式。字符串在静态分配的缓冲区中返回,后续调用将覆盖该缓冲区



To be able to convert both (IPv4 and IPv6) struct sockaddr_XYZ's binary addresses to a char[]use inet_ntop().

为了能够将(IPv4 和 IPv6)struct sockaddr_XYZ的二进制地址都转换为char[]使用inet_ntop().

回答by glglgl

The counterpart of getaddrinfo()is getnameinfo(). This turns a struct sockaddrinto a string.

的对应物getaddrinfo()getnameinfo()。这会将 astruct sockaddr转换为字符串。