C网络函数getaddrinfo

本文详细介绍了C语言中的网络函数getaddrinfo,包括相关数据结构如struct addrinfo、sockaddr及其子结构,以及如何进行IPv4和IPv6地址的转换。通过示例代码展示了getaddrinfo的使用方法,用于获取主机的IP地址信息。
结构struct:
struct addrinfo {
    int              ai_flags;     // AI_PASSIVE, AI_CANONNAME, etc.
    int              ai_family;    // AF_INET, AF_INET6, AF_UNSPEC通信类型
    int              ai_socktype;  // SOCK_STREAM, SOCK_DGRAM
    int              ai_protocol;  // use 0 for "any"
    size_t           ai_addrlen;   // size of ai_addr in bytes
    struct sockaddr *ai_addr;      // struct sockaddr_in or _in6  存储地址和端口的指针<见下面的结构定义>
    char            *ai_canonname; // full canonical hostname

    struct addrinfo *ai_next;      // linked list, next node     返回的结构链表指针
};
下面的sockaddr 存储地址信息,这里一眼还看不到任何的有用的信息
struct sockaddr {
    unsigned short    sa_family;    // address family, AF_xxx
    char              sa_data[14];  // 14 bytes of protocol address
};
但是从下面的结构就可一看到具体的地址等有效信息,有用的信息是:struct sockaddr指针和 struct sockaddr_in指针可以相互转换,着就方便了读取地址中的各部分信息。
// (IPv4 only--see struct sockaddr_in6 for IPv6)
struct sockaddr_in {
    short int          sin_family;  // Address family, AF_INET
    unsigned short int sin_port;    // Port number
    struct in_addr     sin_addr;    // Internet address 32bit表示,并非我们通常说的点分模式
    unsigned char      sin_zero[8]; // Same size as struct sockaddr
};
其中struct in_addr如下定义
// Internet address (a structure for historical reasons)
struct in_addr {
    uint32_t s_addr; // that's a 32-bit int (4 bytes)
};
对于ipv6的结构可以参考如下
struct sockaddr_in6 {
    u_int16_t       sin6_family;   // address family, AF_INET6
    u_int16_t       sin6_port;     // port number, Network Byte Order
    u_int32_t       sin6_flowinfo; // IPv6 flow information
    struct in6_addr sin6_addr;     // IPv6 address
    u_int32_t       sin6_scope_id; // Scope ID
};

struct in6_addr {
    unsigned char   s6_addr[16];   // IPv6 address
};

/———————————————————————————————————结构至此—————————————————————————————————————————————/
地址的转换问题,由点分到in_addr(也就时位模式)
struct sockaddr_in in4;
struct sockaddr_in6 in6;
inet_pton(AF_INET, "192.0.2.1", &(sa.sin_addr)); // IPv4
inet_pton(AF_INET6, "2001:db8:63b3:1::3490", &(sa6.sin6_addr)); // IPv6
参数:0:网络类型(AF_INET or AF_INET6)1:点分模式(ipv6冒号隔开)3:转换的地址后存储位置指针
               由位模式转换为点分模式(char *模式)eg.
char ipv4[INET_ADDRSTRLEN]; //足够的长度存储
char ipv6[INET6_ADDRSTRLEN];//
inet_ntop(AF_INET, &(sa.sin_addr), ipv4, sizeof ipv4);
inet_ntop(AF_INET6, &(sa.sin6_addr), ipv6, sizeof ipv6);
参数:0:
网络类型(AF_INET or AF_INET6)1:为模式的指针 3:转换的地址后存储位置指针,4存储大小。
下面看getaddrinfo函数,次函数兼容ipv6
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

int getaddrinfo(const char *node,     // e.g. "www.example.com" or IP
                const char *service,  // e.g. "http" or port number
                const struct addrinfo *hints,
                struct addrinfo **res);
参数:0:host or IP
      1:service Linux 下可以通过gedit /etc/services 查看
      2:hints 是一个你预先配的结构,填充你想要相关信息的信息
      3:res 起始就是一个指向返回的 Linked List 的指针
由于返回的List时动态的所有在最后要释放这些结构链表,通过一个结构就可以做到:
freeaddrinfo(res);
一个例子:
/*
** showip.c -- show IP addresses for a host given on the command line
*/

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
    struct addrinfo hints, *res, *p;
    int status;
    char ipstr[INET6_ADDRSTRLEN];

    if (argc != 2) {
        fprintf(stderr,"usage: showip hostname\n");
        return 1;
    }

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version
    hints.ai_socktype = SOCK_STREAM;

    if ((status = getaddrinfo(argv[1], NULL, &hints, &res)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
        return 2;
    }

    printf("IP addresses for %s:\n\n", argv[1]);

    for(p = res;p != NULL; p = p->ai_next) {
        void *addr;
        char *ipver;

        // get the pointer to the address itself,
        // different fields in IPv4 and IPv6:
        if (p->ai_family == AF_INET) { // IPv4
            struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
            addr = &(ipv4->sin_addr);
            ipver = "IPv4";
        } else { // IPv6
            struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
            addr = &(ipv6->sin6_addr);
            ipver = "IPv6";
        }

        // convert the IP to a string and print it:
        inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
        printf("  %s: %s\n", ipver, ipstr);
    }

    freeaddrinfo(res); // free the linked list

    return 0;
}
run:
showip www.baidu.com
The IP address for www.baidu.com is
IPV4: 119.75.218.70
IPV4: 119.75.217.109
 
 
本文参考了http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html
其他资料:http://blog.youkuaiyun.com/xjtuse_mal/article/details/1967471http://blog.youkuaiyun.com/xjtuse_mal/article/details/1967471
          man手册:man getaddrinfo

                
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值