libevent笔记-dns解析

来源:互联网 发布:盖洛普q12数据分析 编辑:程序博客网 时间:2024/05/17 21:52
//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);}

0 0