五十七、linux 编程——UDP 编程 域名解析
57.1 介绍
57.1.1 域名解析
57.1.2 域名解析函数
gethostent 可以获取多组,gethostbyname 只可以获取一组
/etc/hosts 文件设置了域名和 IP 的绑定关系
57.2 例子
57.2.1 例子1
gethost.c
1 #include <netdb.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <memory.h> 5 #include <arpa/inet.h> 6 7 8 void out_addr(struct hostent *h) 9 { 10 printf("hostname: %s\n", h->h_name); 11 printf("addrtype: %s\n", h->h_addrtype == AF_INET ? "IPV4": "IPV6"); 12 char ip[16]; 13 memset(ip, 0, sizeof(ip)); 14 inet_ntop(h->h_addrtype, h->h_addr_list[0], ip, sizeof(ip)); 15 printf("ip address: %s\n", ip); 16 17 int i = 0; 18 while(h->h_aliases[i] != NULL){ 19 printf("aliase: %s\n", h->h_aliases[i]); 20 i++; 21 } 22 } 23 24 int main(int argc, char *argv[]) 25 { 26 if(argc < 2){ 27 printf("usage: %s host\n", argv[0]); 28 exit(1); 29 } 30 31 struct hostent *h; 32 h = gethostbyname(argv[1]); 33 if( NULL != h){ 34 out_addr(h); 35 } 36 else{ 37 perror("get hostbyname error"); 38 } 39 40 return 0; 41 }
修改下 /etc/hosts 文件,给 localhost 增加一个别名
编译运行:
gethostbyname 有一些缺陷,支持 IPV4 但是不支持 IPV6,且不能用于多线程中。
57.2.2 例子2
gethost2.c
1 #include <netdb.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <memory.h> 5 #include <arpa/inet.h> 6 7 8 void out_addr(struct hostent *h) 9 { 10 printf("hostname: %s\n", h->h_name); 11 printf("addrtype: %s\n", h->h_addrtype == AF_INET ? "IPV4": "IPV6"); 12 char ip[16]; 13 memset(ip, 0, sizeof(ip)); 14 inet_ntop(h->h_addrtype, h->h_addr_list[0], ip, sizeof(ip)); 15 printf("ip address: %s\n", ip); 16 17 int i = 0; 18 while(h->h_aliases[i] != NULL){ 19 printf("aliase: %s\n", h->h_aliases[i]); 20 i++; 21 } 22 } 23 24 int main(int argc, char *argv[]) 25 { 26 if(argc < 2){ 27 fprintf(stderr, "usage: %s host\n", argv[0]); 28 exit(1); 29 } 30 31 struct hostent *h; 32 while((h = gethostent()) != NULL){ 33 if(!strcmp(argv[1], h->h_name)){ 34 out_addr(h); 35 exit(0); 36 } 37 else{ 38 int i = 0; 39 while(h->h_aliases[i] != NULL){ 40 if(!strcmp(argv[1], h->h_aliases[i])){ 41 out_addr(h); 42 exit(0); 43 } 44 i++; 45 } 46 } 47 } 48 49 endhostent(); 50 printf("no %s exist\n", argv[1]); 51 52 return 0; 53 }
编译运行:
57.2.3 例子3
修改前面 time_udp_client.c 文件
1 #include <sys/types.h> 2 #include <sys/socket.h> 3 #include <arpa/inet.h> 4 #include <unistd.h> 5 #include <netdb.h> 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <signal.h> 9 #include <string.h> 10 #include <time.h> 11 12 int is_host(struct hostent *host, char *name) 13 { 14 if(!strcmp(host->h_name, name)) return 1; 15 int i = 0; 16 while(host->h_aliases[i] != NULL){ 17 if(!strcmp(host->h_aliases[i], name)) return 1; 18 i++; 19 } 20 21 return 0; 22 } 23 24 unsigned int get_ip_by_name(char *name) 25 { 26 unsigned int ip = 0; 27 struct hostent *host; 28 while((host = gethostent()) != NULL){ 29 if(is_host(host, name)){ 30 memcpy(&ip, host->h_addr_list[0], 4); 31 break; 32 } 33 } 34 35 endhostent(); 36 return ip; 37 } 38 39 int main(int argc, char *argv[]) 40 { 41 if(argc < 3){ 42 printf("usage: %s ip port\n", argv[0]); 43 exit(1); 44 } 45 46 /** 步骤1: 创建 socket */ 47 int sockfd = socket(AF_INET, SOCK_DGRAM, 0); 48 if(sockfd < 0){ 49 perror("socket error"); 50 exit(1); 51 } 52 53 /** 步骤2: 调用 recvfrom 和 sendto 等函数和服务器端双向通信 */ 54 struct sockaddr_in serveraddr; 55 memset(&serveraddr, 0, sizeof(serveraddr)); 56 serveraddr.sin_family = AF_INET; ///< ipv4 57 serveraddr.sin_port = htons(atoi(argv[2])); ///< port 58 59 unsigned int ip = get_ip_by_name(argv[1]); 60 if(ip != 0){ 61 serveraddr.sin_addr.s_addr = ip; 62 } 63 else { 64 inet_pton(AF_INET, argv[1], &serveraddr.sin_addr.s_addr); 65 } 66 67 char buffer[1024] = "hello world"; 68 /** 向服务器端发送数据报文 */ 69 if(sendto(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0){ 70 perror("sendto error"); 71 exit(1); 72 } 73 else{ 74 /** 接受服务器端发送的数据报文 */ 75 memset(buffer, 0, sizeof(buffer)); 76 if(recv(sockfd, buffer, sizeof(buffer), 0) < 0){ 77 perror("recv error"); 78 exit(1); 79 } 80 else{ 81 printf("%s", buffer); 82 } 83 } 84 85 close(sockfd); 86 87 return 0; 88 }
编译,运行服务器和客户端测试: