getnameinfo使用

这个函数与getaddrinfo互补,它以一个套接口地址为参数,返回一个描述主机的字符串和一个描述服务的字符串。

头文件

#include <sys/socket.h>
#include <netdb.h>

函数原型

int getnameinfo(const struct sockaddr *sa, socklen_t salen,
                       char *host, size_t hostlen,
                       char *serv, size_t servlen, int flags);

参数

flags该标志的说法是,改变功能的默认操作的标志。默认情况下,应返回主机的完全限定域名(FQDN),但是:

  • 如果设置了标志位NI_NOFQDN,则只应为本地主机返回FQDN的节点名称部分。
  • 如果设置了标志位NI_NUMERICHOST ,则在所有情况下都应返回sa参数指向的套接字地址结构中包含的地址的数字形式而不是其名称。
  • 如果设置了标志位NI_NAMEREQD,则如果找不到主机名,则应返回错误。
  • 如果设置了标志位NI_NUMERICSERV,则在所有情况下都应返回服务地址的数字形式(例如,其端口号)而不是其名称。
  • 如果设置了标志位NI_NUMERICSCOPE,则应返回范围标识符的数字形式(例如,接口索引)而不是其名称。如果sa参数不是IPv6地址,则应忽略此标志。
  • 如果设置了标志位NI_DGRAM,则表明该服务是数据报服务(SOCK_DGRAM)。默认行为应假定该服务是流服务(SOCK_STREAM)。

返回值

getnameinfo()的零返回值表示成功完成; 非零返回值表示失败。错误的可能值列在“错误”部分中。

成功完成后,getnameinfo()将在提供的缓冲区中返回节点和服务名称(如果请求)。返回的名称始终以空字符结尾的字符串。

错误

如果出现以下情况,getnameinfo()函数将失败并返回相应的值:

[EAI_AGAIN]
目前无法解析该名称。未来的尝试可能成功。
[EAI_BADFLAGS]
该标志有一个无效值。
[EAI_FAIL]
发生了不可恢复的错误。
[EAI_FAMILY]
未识别地址系列或指定系列的地址长度无效。
[EAI_MEMORY]
存在内存分配失败。
[EAI_NONAME]
名称无法解析提供的参数。
NI_NAMEREQD已设置且无法找到主机名,或者nodename和servname均为null。

[EAI_OVERFLOW]
参数缓冲区溢出。node参数或service参数指向的缓冲区太小。
[EAI_SYSTEM]
发生系统错误。错误代码可以在errno中找到。

addrinfo 结构体定义

struct addrinfo {
	int     ai_flags;
	int     ai_family;
	int     ai_socktype;
	int     ai_protocol;
	size_t  ai_addrlen;
	struct sockaddr *ai_addr;
	char   *ai_canonname;
	struct addrinfo *ai_next;
 };

示例1:

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main(int argc, char *argv[])
{
        int ret;
        char *ptr;
        char hostname[128] = {0};
        char servername[128] = {0};
        struct sockaddr_in addr_dst;

        ptr = argc < 2 ? "180.101.49.11" : argv[1];

        memset(&addr_dst,0,sizeof(addr_dst));
        addr_dst.sin_family = AF_INET;
        addr_dst.sin_addr.s_addr =  inet_addr(ptr);

        
        ret = getnameinfo((struct sockaddr *)&addr_dst, sizeof(addr_dst), hostname, sizeof(hostname), servername, sizeof(servername), 0);
        if (ret != 0)
        {
                fprintf(stderr, "error in getnameinfo: %s \n", gai_strerror(ret));
        }
        else
        {
                printf("hostname IP: %s \n", hostname);
                printf("servername IP: %s \n", servername);
        }


        exit(EXIT_SUCCESS);
}

示例2:

/* hostname_to_ip hostname */

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main(int argc, char *argv[])
{
        if (argc != 2)
        {
                fprintf(stderr, "Usage: %s hostname\n", argv[0]);
                exit(EXIT_FAILURE);
        }
        struct addrinfo hints;
        struct addrinfo *result, *result_pointer;
        int ret;
        /* obtaining address matching host */
        memset(&hints, 0, sizeof(struct addrinfo));
        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_flags = AI_CANONNAME;
        hints.ai_protocol = 0;  /* any protocol */
                                                                                                          
        ret = getaddrinfo(argv[1], NULL, &hints, &result);
        if (ret != 0)
        {
                fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
                exit(EXIT_FAILURE);
        }
        /* traverse the returned list and output the ip addresses */
        for (result_pointer = result; result_pointer != NULL; result_pointer = result_pointer->ai_next)
        {
                char hostname[1025] = "";
                //flags = NI_NUMERICHOST 表示任何情况下都返回数字形式地址
                ret = getnameinfo(result_pointer->ai_addr, result_pointer->ai_addrlen, hostname, sizeof(hostname), NULL, 0, NI_NUMERICHOST);
                if (ret != 0)
                {
                        fprintf(stderr, "error in getnameinfo: %s \n", gai_strerror(ret));
                        continue;
                }
                else
                {
                        printf("IP: %s \n", hostname);
                }
        }
        freeaddrinfo(result);
        exit(EXIT_SUCCESS);
}

打印hostname有些事域名,如8.8.8.8或114.114.114.114,有些是IP的二进制子串;

参考资料
http://pubs.opengroup.org/onlinepubs/009695399/functions/getnameinfo.html
https://blog.csdn.net/xiexingshishu/article/details/40018589
https://blog.csdn.net/jctian000/article/details/81912346
http://cache.baiducontent.com/c?m=9d78d513d99616e904becb29564a833b0d13c03d338d96533dc3923b8e791e040271e3cc766052548d98297001d81801b5ed62377d5b78aac888d91086ffc5352f8a24346d1f855c11d304acc04127c424875a9ef55fb8e4&p=9263c21a86cc42a41a9fc7710f53&newp=8e49f90ecd8512a05abd9b7d065092695d0fc20e3ad2d501298ffe0cc4241a1a1a3aecbf22211a00d2c17c660aad4b5fecfa31723d0034f1f689df08d2ecce7e&user=baidu&fm=sc&query=getnameinfo&qid=a8eb58a4000006e4&p1=7

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值