C语言编写异步域名查询程序,可提升查询效率,避免阻塞。
在C语言中实现异步域名查询程序,可以采用多种方法,以下是几种常见的实现方式及其详细描述:
1、基于select/poll/epoll的异步查询
原理:select、poll和epoll是Linux系统下用于监控文件描述符状态变化的系统调用,在异步域名查询中,可以将套接字描述符注册到这些监控机制中,当域名查询的套接字有可读事件发生时(即域名解析结果返回),便能及时处理,而不会阻塞主线程去等待查询结果。
实现步骤
创建一个套接字,并设置为非阻塞模式。
使用getaddrinfo
函数发起域名解析请求,将套接字与域名解析服务关联起来。
将套接字描述符添加到select、poll或epoll的监控列表中。
主线程继续执行其他任务,同时监控监控列表,当监控机制检测到套接字有可读事件时,从套接字中读取域名解析结果。
示例代码(使用select)
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <unistd.h> #include <arpa/inet.h> #include <fcntl.h> #include <errno.h> #define MAX_FD_NUM 1024 int make_socket_non_blocking(int sockfd) { int flags = fcntl(sockfd, F_GETFL, 0); if (flags == -1) { perror("fcntl"); return -1; } flags |= O_NONBLOCK; if (fcntl(sockfd, F_SETFL, flags) == -1) { perror("fcntl"); return -1; } return 0; } int main() { struct addrinfo hints, res; int sockfd; char host[] = "www.example.com"; fd_set readfds; struct timeval tv; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; // Allow IPv4 or IPv6 hints.ai_socktype = SOCK_STREAM; if (getaddrinfo(host, NULL, &hints, &res) != 0) { perror("getaddrinfo"); exit(EXIT_FAILURE); } sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sockfd == -1) { perror("socket"); freeaddrinfo(res); exit(EXIT_FAILURE); } if (make_socket_non_blocking(sockfd) == -1) { close(sockfd); freeaddrinfo(res); exit(EXIT_FAILURE); } connect(sockfd, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); while (1) { FD_ZERO(&readfds); FD_SET(sockfd, &readfds); tv.tv_sec = 5; // Timeout of 5 seconds tv.tv_usec = 0; int ret = select(sockfd + 1, &readfds, NULL, NULL, &tv); if (ret == -1) { perror("select"); break; } else if (ret == 0) { printf("Timeout occurred! "); break; } else if (FD_ISSET(sockfd, &readfds)) { char buffer[1024]; int n = recv(sockfd, buffer, sizeof(buffer), 0); if (n <= 0) { if (n < 0) perror("recv"); break; } buffer[n] = '