libevent笔记-dns解析

//libevent笔记-dns解析
//转载请注明出处: yuliying的csdn博客.

//libevent提供dns解析功能,包括阻塞和非阻塞两种API.
//阻塞API类似于平常getaddrinfo() 函数的使用.
//这里只记录异步API的dns客户端部分.毕竟平常阻塞api和dns服务端用不着.

//=============================evutil_addrinfo结构===========================================
//evutil_addrinfo结构的作用有两个: ①用来返回域名解析的结果. ②作为参数用来过滤域名解析结果,只返回符合条件的结果.
/* 和系统头文件提供的addrinfo结构基本一样:
struct evutil_addrinfo {
    int ai_flags; // 指定如何来处理地址和名字
    int ai_family; // 地址类型 : AF_INET,AF_INET6,AF_UNIX etc
    int ai_socktype;  // 套接字类型 SOCK_STREAM,SOCK_DATAGRAM,SOCK_RAW
    int ai_protocol;  // 协议 IPPROTO_IP, IPPROTO_IPV4, IPPROTO_IPV6 etc
    size_t ai_addrlen; // 地址长度
    char *ai_canonname; // 主机规范名
    struct sockaddr *ai_addr; // 地址
    struct evutil_addrinfo *ai_next; // 链表中的下一个结构
};
*/

//=====ai_flags 用来指定如何处理地址和名字,可用标志有:
//AI_ADDRCONFIG :查询配置的地址类型(IPv4或IPv6)。
//AI_ALL :查找IPv4和IPv6地址,仅用于 AI_V4MAPPED 。
//AI_CANONNAME :需要一个规范名而不是别名。
//AI_NUMERICHOST :以数字格式返回主机地址。
//AI_NUMERICSERV :以端口号返回服务。
//AI_PASSIVE :套接字地址用于监听绑定。
//AI_V4MAPPED :如果没找到IPv6地址,返回映射到IPv6格式的IPv4地址。

//======解析域名时可以使用hints参数来过滤返回的地址,它是一个evutil_addrinfo结构.
//它只使用 ai_flags、ai_family、ai_socktype、ai_protocol字段其他字段必须设为0或 NULL.

//======释放evutil_addrinfo结构
//	void evutil_freeaddrinfo(struct evutil_addrinfo *ai);

//=============================evdns_base结构================================================
//evdns_base结构用来存储域名解析服务器地址和解析的配置.使用 evdns_base_new() 函数来创建.
//函数原型如下:
//struct evdns_base *evdns_base_new(struct event_base *event_base, int initialize);
//失败时返回NULL.
//如果initialize参数设置为1,则使用操作系统的默认配置.如果为0,则不设置域名解析服务器和配置参数.
//可以使用evdns_base_resolv_conf_parse()函数来读取一个配置文件,实现自定义配置,这里就不多说了.

//以下函数用来配置一个evdns_base:
//===========添加一个域名服务器(使用sockaddr结构): 
//	int evdns_base_nameserver_sockaddr_add(struct evdns_base *base,const struct sockaddr *sa, ev_socklen_t len , unsigned flags);
//flag参数暂时没用,设置为0. 成功返回0,失败返回负数.

//===========添加一个域名服务器(使用ip地址):
//	int evdns_base_nameserver_ip_add(struct evdns_base *base , const char *ip_as_string);
//成功返回0,失败返回负数. ip地址格式为"IPv4:Port" 或者 "[IPv6]:Port"

//===========添加域名服务器(使用host文件) :
//	int evdns_base_load_hosts(struct evdns_base *base, const char *hosts_fname);
//成功返回0,失败返回负数.

//===========使用 evdns_base_free()函数来释放 evdns_base结构.
//	void evdns_base_free(struct evdns_base *base, int fail_requests);
//如果fail_requests参数为true, 会调用所有未完成任务的回调函数,并且错误码为取消任务.

//=============================异步解析回调函数=============================================
//回调函数的原型是:
//	typedef void (*evdns_getaddrinfo_cb)(int result, struct evutil_addrinfo *res, void *arg);
//result为0表示成功,具体错误码参照手册.
//可以使用  const char *evutil_gai_strerror(int err); 函数来把error 信息打印出来.


//===========================使用evdns_getaddrinfo()函数来异步解析dns=======================
//函数原型如下: 
//struct evdns_getaddrinfo_request *evdns_getaddrinfo( struct evdns_base *dns_base , const char *nodename, 
//  const char *servname, const struct evutil_addrinfo *hints ,evdns_getaddrinfo_cb cb, void *arg);

//nodename 参数和 servname 参数需要至少一个不为NULL.
//nodename 参数的格式为: ipv4地址("127.0.0.1") 或者 ipv6地址("::1") 或者 网址("www.example.com")
//servname 参数的格式为: 协议名称("https") 或者 端口号("443")
//hints 参数为过滤选项.
//cb参数为回调函数.
//arg参数为用户自定义参数,作为回调函数的参数.
//如果 evdns_getaddrinfo 失败或者立刻成功,返回NULL. 否则返回一个 evdns_getaddrinfo_request 结构体.
//我们使用evdns_getaddrinfo_request结构体和evdns_getaddrinfo_cancel()函数可以用来取消解析.
//cb 回调函数无论如何都会被调用,即使是取消了解析.
//当evdns_getaddrinfo() 函数被调用时,内部保存了nodename,servname和hints参数的拷贝,如果是动态分配的内存我们可以在调用后回收.

#include <event2/event.h>
#include <event2/util.h>
#include <event2/dns.h>
#include <string.h>
#include <stdlib.h>

struct event_base *base = NULL;

void callback(int errcode, struct evutil_addrinfo *addr, void *ptr){
	if (errcode) {
		printf("error : %s\n" , evutil_gai_strerror(errcode) );
	} else {
		struct evutil_addrinfo *ai;
		if (addr->ai_canonname){
			printf( "cannoname:[%s]\n" , addr->ai_canonname);
		}
		//addr是一个链表,遍历链表
		for( ai = addr ; ai ; ai = ai->ai_next){
			char buf[128];
			const char *s = NULL;
			if ( ai->ai_family == AF_INET){
				struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr;
				s = evutil_inet_ntop(AF_INET, &sin->sin_addr, buf, 128);
			} else if ( ai->ai_family == AF_INET6){
				struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr;
				s = evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf, 128);
			}
			if (s){
				printf("  ->%s\n" , s);
			}
		}
		evutil_freeaddrinfo(addr);
	}
}


int main(){
	//event_base是必须的.
	base = event_base_new();
	//使用系统默认配置
	struct evdns_base *dnsbase = evdns_base_new(base, 1);
	//用来过滤返回的地址信息.
	struct evutil_addrinfo hints;
	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_UNSPEC ; //不指定.
	hints.ai_flags = EVUTIL_AI_CANONNAME; //返回规范名.
	hints.ai_socktype = SOCK_STREAM; //只需要SOCK_STREAM套接字类型
	hints.ai_protocol = IPPROTO_TCP; //只需要TCP协议的.
	//
	const char* nodename = "www.baidu.com";
	struct evdns_getaddrinfo_request *req;
	req = evdns_getaddrinfo(dnsbase , nodename , NULL , &hints , callback , NULL);
	//
	event_base_dispatch(base);
	//
	if ( req != NULL) free( req );
	//
	evdns_base_free(dnsbase, 0);
    event_base_free(base);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值