专栏首页CSDN搜“看,未来”通过域名获取主机IP -- struct addrinfo

通过域名获取主机IP -- struct addrinfo

参考书籍:《UNIX环境高级编程》 (APUE,男神的书,出第三版了,有需要的私信我)

文章目录
  • 结构体定义
    • 参数释义:
      • ai_flags
    • ai_family
    • ai_socktype
    • ai_protocol
    • ai_next
  • 相关函数
    • getaddrinfo
      • 参数释义:
      • 返回值
      • 栗子
    • freeaddrinfo
  • 使用示例
    • 亲测:

结构体定义

addrinfo结构主要在网络编程解析hostname时使用,其在头文件#include<netdb.h>中,定义如下:

struct addrinfo
{
  int ai_flags;                 /* Input flags.  */
  int ai_family;                /* Protocol family for socket.  */
  int ai_socktype;              /* Socket type.  */
  int ai_protocol;              /* Protocol for socket.  */
  socklen_t ai_addrlen;         /* Length of socket address.  */
  struct sockaddr *ai_addr;     /* Socket address for socket.  */
  char *ai_canonname;           /* Canonical name for service location.  */
  struct addrinfo *ai_next;     /* Pointer to next in list.  */
};

可以说是新面孔,也可以说是老面孔,那我来介绍一下? 那就介绍一下:好的其实它的介绍已经挺明白了。

跟sin_addr和s_addr差不多。

参数释义:

ai_flags

用来指定如何处理地址和名字,可取得值如下:

就改个前缀,是吧

ai_family

这里直接连前缀都不改了

ai_socktype

同上

ai_protocol

IPPROTO_IP 	:IP协议
IPPROTO_IPV4 	:IPv4
IPPROTO_IPV6 	:IPv6
IPPROTO_TCP 	:TCP
IPPROTO_UDP	:UDP

这个改动的东西比较多。

ai_next

由于一个域名可以对应多个IP地址,addrinfo也就支持了这个场景。addrinfo通过链表的方式存储其他地址的,可以遍历其属性ai_next获得。

相关函数

getaddrinfo

找了一圈也找不到它的源码,只能把声明贴出来了,什么时候找着了再补上来。

int getaddrinfo(const char *restrict nodename, /* host 或者IP地址 */
    const char *restrict servname, /* 十进制端口号 或者常用服务名称如"ftp"、"http"等 */
    const struct addrinfo *restrict hints, /* 获取信息要求设置 */
    struct addrinfo **restrict res); /* 获取信息结果 */

参数释义:

nodename: 主机名(“lion-wu.blog.csdn.net”)或者是数字化的地址字符串(IPv4的点分十进制串(“192.168.128.64”)或者IPv6的16进制串)。 如果 ai_flags 中设置了AI_NUMERICHOST 标志,那么该参数只能是数字化的地址字符串,不能是域名,该标志的作用就是阻止进行域名解析。 nodename 和 servname 可以设置为NULL,但是同时只能有一个为NULL。

servname: 服务名可以是十进制的端口号(“8080”)字符串,也可以是已定义的服务名称,如"ftp"、"http"等,详细请查看/etc/services 文件,最后翻译成对应服务的端口号。如果此参数设置为NULL,那么返回的socket地址中的端口号不会被设置。 如果 ai_flags 设置了AI_NUMERICSERV 标志并且该参数未设置为NULL,那么该参数必须是一个指向10进制的端口号字符串,不能设定成服务名,该标志就是用来阻止服务名解析。

hints: 该参数指向用户设定的 struct addrinfo 结构体,只能设定该结构体中 ai_family、ai_socktype、ai_protocol 和 ai_flags 四个域,其他域必须设置为0 或者 NULL, 通常是申请 结构体变量后使用memset()初始化再设定指定的四个域。 该参数可以设置为NULL,等价于 ai_socktype = 0, ai_protocol = 0,ai_family = AF_UNSPEC,ai_flags = 0。

res: 该参数获取一个指向存储结果的 struct addrinfo 结构体列表,使用完成后调用 freeaddrinfo() 释放存储结果空间。

返回值

如果 getaddrinfo() 函数执行成功,返回值为 0 , 其他情况返回值表示错误种别。使用函数gai_strerror() 可以获取可读性的错误信息,用法用strerror()相同。

栗子

 ret = getaddrinfo("lion-wu.blog.csdn.net", NULL, &hint, &res);
    if (ret != 0) 
    {
        printf("getaddrinfo error\n");
        return -1;
    }

freeaddrinfo

void freeaddrinfo(struct addrinfo *ai)
{
    struct addrinfo *next;

#if defined(__BIONIC__)
    if (ai == NULL) return;
#else
    _DIAGASSERT(ai != NULL);
#endif

    do {
        next = ai->ai_next;
        if (ai->ai_canonname)
            free(ai->ai_canonname);
        /* no need to free(ai->ai_addr) */
        free(ai);
        ai = next;
    } while (ai);
}

使用示例

#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>

int main(int argc, char **argv)
{
    int ret = -1;
    struct addrinfo *res;
    struct addrinfo hint;
    struct addrinfo *curr;
    char ipstr[16];   

    if (argc != 2) {
        printf("parameter error\n");
        return -1;
    }

    bzero(&hint, sizeof(hint));
    hint.ai_family = AF_INET;
    hint.ai_socktype = SOCK_STREAM;

    ret = getaddrinfo(argv[1], NULL, &hint, &res);
    if (ret != 0) 
    {
        printf("getaddrinfo error\n");
        return -1;
    }

    for (curr = res; curr != NULL; curr = curr->ai_next) 
    {
        inet_ntop(AF_INET,&(((struct sockaddr_in *)(curr->ai_addr))->sin_addr), ipstr, 16);
        printf("%s\n", ipstr);
    }

    freeaddrinfo(res);

    return 0;
}

亲测:

能猜到为啥第一次操作失败了吗?


今天的技术介绍就到这里啦,我要介绍一位我的新朋友: 唔仄lo咚锵 我们学校软件工程系的大佬,Java、算法、redis领域博主,正在厚积薄发当中。

然后,顺便也可以看看我的其他博客,lion-wu.blog.csdn.net

刷一下就过去了,确定不留下吗?

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 文件I/O

    有一定编程基础的小伙伴应该都接触过文件编程吧,file. 在C语言里面是包一个<file.h>的头

    看、未来
  • 可重入函数对于线程安全的意义(附函数表)

    不可重入函数: 在并发服务器中,经常会出现多个任务调用同一个函数的情况,比方说后端服务器使用多线程同时对数据库进行访问操作。如果有一个函数不幸被设计成为这样:...

    看、未来
  • anetTcpGenericConnect 详解

    看、未来
  • 线性表抽象数据结构的定义

    鲁郭大侠
  • RSAC 2020创新沙盒冠军正式揭晓!SECURITI.ai解决隐私合规问题

    美国当地时间2月24日(北京时间2月25日),备受瞩目的全球盛会RSA 2020在旧金山正式开幕。在当天下午,这个被称为“网络安全风向标”的创新沙盒环节正式揭晓...

    FB客服
  • struct2 拿到url的方法

    在Action中: HttpServletRequest request = ServletActionContext.getRequest(); Stri...

    ydymz
  • 不同浏览器对于换行的处理

    在一个容器中,如果设定了宽度,一般来说自动换行都是比较正常的,但是如果遇到了连续的英文字符,这个问题就会让人头疼。这不,我们部门的用户在测试的时候输入连续的字符...

    大江小浪
  • 单链表反转Java版

    在头节点的后面进行插入操作,后一个插入进来的值,在前一个插入进来的值与头节点之间。

    汐楓
  • Codeforces Round #550 (Div. 3) D. Equalize Them All(思维)

    版权声明:欢迎转载,若转载,请标明出处,如有错误,请指点,也欢迎大佬们给出优化方法 https://blog.csdn.net/Charles_Zaqd...

    Ch_Zaqdt
  • Android JNI学习(三)——Java与Native相互调用

    前面两篇文章简单的介绍了JNI,下面我们就进一步了解下一下JNI的调用原则,要想了解JNI的调用原则, 前面我们说了JNI中的JNIEnv以及Java类型和na...

    隔壁老李头

扫码关注云+社区

领取腾讯云代金券