2. 端口绑定和域名解析
2.1 端口绑定:SO_REUSEADDR选项
int opt = 1;//1表示启用该选项 //设置为可重新使用端口,每次启动该端口时,会重新绑定端口。相当于端口被复位并被重新。 //绑定。因此,以后以最后这次绑定为准 if((ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) < 0){ perror("setsockopt error"); exit(1); }
2.2 域名解析
(1)域名解析过程
(2)域名解析函数
头文件 |
#include <netdb.h> |
函数 |
struct hostent* gethostent(void); struct hostent* gethostbyname(const char* hostname); void sethostent(int stayopen); void endhostent(void); //注意get和endhostent应成对使用! |
参数 |
struct hostent{ char* h_name; //正式主机名 char** h_aliases; //别名,字符串数组 int h_addrtype; //协议类型 int h_length; //网络地址大小 char** h_addr_list;//指向网络地址的指针 }; |
功能 |
域名解析 |
备注 |
查看域名和IP映射关系:#more /etc/hosts |
(3)hostent结构体
(4)域名解析案例
//域名解析,并将结果保存在hostent结构体中 if((hptr = gethostbyname("www.google.com")) == NULL){ fprintf(stderr, "gethostbyname call failed.%s\n", hstrerror(h_errno)); return -1; } printf("official name: %s\n", hptr->h_name); //输出正式名 for(pptr = hptr->h_aliases; *pptr != NULL; pptr++){ //输出对应各个别名 printf("\t alias: %s\n", *pptr); } if(hptr->h_addrtype != AF_INET){ //判断是否为IPv4地址 fprintf(stderr, "Invalid address type %d\n", hptr->addrtype); return -1; } pptr = hptr->h_addr_list; for(; *pptr != NULL; pptr++){ //输出点分十进制的IP地址(字符串) printf("\t address: %s\n", inet_ntop(hptr->h_addrtype, *pptr, str, sizeof(str))); }
【编程实验】根据域名解析出IP地址
//gethost.c
#include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <memory.h> #include <string.h> int is_host(struct hostent* host, char* name) { //如果正式名为name,则直接返回 if(!strcmp(host->h_name, name)) return 1; //查找别名为name int i = 0; while(host->h_aliases[i] != NULL){ if(!strcmp(host->h_aliases[i], name)) return 1; i++; } } //根据主机名获取IP unsigned int get_ip_by_name(char* name) { unsigned int ip = 0; struct hostent* host; //遍历/etc/hosts文件,找出所有的主机名。 //每调用一次gethostent将读取文件的一行(对应一个主机) while((host = gethostent()) != NULL){ if(is_host(host, name)){ //h_addr_list[0]中所存放在IP是网络字节序,共4个字节。 memcpy(&ip, host->h_addr_list[0], 4); break; } } endhostent(); return ip; } void out_addr(struct hostent* h) { printf("hostname: %s\n", h->h_name); printf("addrtype: %s\n", h->h_addrtype == AF_INET ? "IPv4": "IPv6"); char ip[16]; memset(ip, 0, sizeof(ip)); inet_ntop(h->h_addrtype, h->h_addr_list[0], ip, sizeof(ip));//绑定的第1个IP地址 printf("ip address: %s\n", ip); //别名 int i = 0; while(h->h_aliases[i] != NULL){ printf("aliases: %s\n", h->h_aliases[i]); i++; } } int main(int argc, char* argv[]) { if(argc < 2){ printf("usage: %s host\n", argv[0]); exit(1); } struct hostent* h; h = gethostbyname(argv[1]); if(h != NULL){ out_addr(h); }else{ printf("no %s exist\n", argv[1]); } //根据主机名,输出IP unsigned int ipNet = get_ip_by_name(argv[1]); //网络字节序IP char ip[16]; memset(ip, 0, sizeof(ip)); inet_ntop(AF_INET, &ipNet, ip, sizeof(ip));//绑定的第1个IP地址 printf("ip address: %s\n", ip); return 0; } /*host文件 * [root@localhost 14.udp]# more /etc/hosts * 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 * 192.168.32.100 santaclaus www.5iedu.com * ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 * *输出结果 [root@localhost 14.udp]# bin/gethost santaclaus hostname: santaclaus addrtype: IPv4 ip address: 192.168.32.100 aliases: www.5iedu.com ip address: 192.168.32.100 [root@localhost 14.udp]# bin/gethost www.5iedu.com hostname: santaclaus addrtype: IPv4 ip address: 192.168.32.100 aliases: www.5iedu.com ip address: 192.168.32.100 [root@localhost 14.udp]# bin/gethost localhost hostname: localhost addrtype: IPv4 ip address: 127.0.0.1 aliases: localhost.localdomain aliases: localhost4 aliases: localhost4.localdomain4 aliases: localhost.localdomain aliases: localhost6 aliases: localhost6.localdomain6 ip address: 127.0.0.1 */