1. 程式人生 > >Linux網路程式設計[DNS解析原理,瞭解相關DNS解析的函式]

Linux網路程式設計[DNS解析原理,瞭解相關DNS解析的函式]

Linux網路程式設計[淺析DNS原理,瞭解相關DNS解析的函式]

1.DNS解析的相關原理
2. 域名解析的相關函式

###埠繫結, DNS解析的相關原理
先通過一張圖示來展示一下什麼是DNS:

這裡寫圖片描述

1:每一個域名都是與ip進行繫結的
2:瀏覽器在訪問域名的時候,會自動解析出對應繫結的ip地址
3:整個解析過程涉及到域名解析與域名伺服器

在自己的本機怎麼去進行域名和ip的繫結呢??
linux系統下,可以在本地本間中去設定:
開啟/etc/hosts檔案:
這裡寫圖片描述
從我本機的hosts檔案中可以看到,對應的ip繫結的主機名和自己設定的域名.第一個域名dean稱為正式的主機名字,第二個以後都稱為別名

域名解析的相關函式

1**:域名解析函式中的結構體**

  struct hostent{
    char *h_name ;//正式主機名字(第一個域名)
    char **h_aliases;//主機的別名(主機的別名對應的)
    int h_addrtype;//協議型別
    int h_length;//網路地址大小
    char **h_addr_list;//指向網路地址的指標
  };
上述的結構體放置的就是域名解析出來後放置的結構體

這裡寫圖片描述

從上述圖示中可以看出來,h_aliases指向的都是一個數組
h_addr_list指向的也是一個ip地址的陣列,所以使用的都是二級指標

2:域名解析相關函式

#include<netdb.h>
struct hostent *gethostent(void);
//會將整個hosts檔案下記錄的主機和域名相對應的所有組全部遍歷出來 

strct hostent *gethostbyname(const char *hostname);
引數:hostname 域名,獲取的是指定的hostent
注意:
    gethostbyname是不支援ipv6的,並且在多執行緒的情況下是不穩定的.所有一般情況下都是使用gethostent來進行操作的

void sethostent(int stayopen);
void endhostent(void);

虛擬碼案例部分

struct hostnet *hptr;
if((hptr = gethostbyname("www.google.com")) == NULL){
    printf(stderr,"gethostbyname call failed.%s\n",hosterror(h_errno));
    return -1;
}
//輸出h_name(正式域名)
printf("offical name:%s\n",hptr->h_name);

//輸出別名:
for(pptr = hptr->h_aliases;*pptr!=NULL,pptr++){
    printf("\t aliases:%s\n",*pptr);
}
//輸出網路型別
if(hptr->h_addrtype != AF_INET){
    fprintf(stderr,"invalid address type %d\n",hptr->h_addrtype);
    return -1;
}
pptr  = hptr->h_addr_list;
for(;*pptr!=NULL;pptr++){
    printf("\t address:%s\n",inet_ntop(hptr->h_addrtype,*pptr,str,sizeof(str)));
}

gethostbyname部分的例項程式碼

/*
 * ===========================================================================
 *
 *       Filename:  gethostbyname.c
 *    Description:  
 *        Version:  1.0
 *        Created:  2017年05月14日 21時52分34秒
 *       Revision:  none
 *       Compiler:  gcc
 *         Author:   (), 
 *        Company:  
 *
 * ===========================================================================
 */

#include<stdio.h>
#include<stdlib.h>
#include<netdb.h>
#include<string.h>
#include<sys/socket.h>

void out_host(struct hostent *h){
  //獲取主機名稱
  char *host_name = h->h_name;
  printf("host_name:%s\n",host_name);

  //獲取網路型別
  int host_addrtype = h->h_addrtype;
  if(host_addrtype == AF_INET){
    printf("addrtype:IPV4\n");
  }else{
    printf("addrtype:IPV6\n");
  }
  //獲取主機網路地址的大小
  int host_length = h->h_length;
  printf("host_length:%d\n",host_length);

  //獲取主機的ip,主機的ip對應的是網路地址陣列中的0,記住要將網路位元組序轉換成主機位元組序號
  char ip[16];
  memset(ip,0,sizeof(ip));
  inet_ntop(h->h_addrtype,h->h_addr_list[0],ip,sizeof(ip));
  printf("host ip:%s\n",ip);

  //遍歷去獲取別名
  int aliase_count = 0;
  while( h->h_aliases[aliase_count] != NULL){
    printf("host_aliases[%d]:%s\n",aliase_count,h->h_aliases[aliase_count]);
    aliase_count++;
  }

  //獲取指向網路地址的陣列,
  int host_addr_list_count = 0;
  while(h->h_addr_list[host_addr_list_count] != NULL){
    memset(ip,0,sizeof(ip));
    inet_ntop(h->h_addrtype,h->h_addr_list[host_addr_list_count],ip,sizeof(ip));
    printf("host_addr_list[%d]:%s\n",host_addr_list_count,ip);
    host_addr_list_count++;
  }


}

int main(int argc,char *argv[]){
  if(argc < 2){
    printf("usag %s host \n",argv[0]);
    exit(EXIT_FAILURE);
  }

  struct hostent *h;
  //通過gethostbyname來獲取hostent的結構體指標
  h = gethostbyname(argv[1]);
  if(h == NULL){
    printf("no host :%s\n",argv[1]);
  }else{
    out_host(h);
  }

  endhostent();
  return 0;
}

gethostent部分的例項程式碼

/*
 * ===========================================================================
 *
 *       Filename:  gethostent.c
 *    Description:  
 *        Version:  1.0
 *        Created:  2017年05月14日 22時14分48秒
 *       Revision:  none
 *       Compiler:  gcc
 *         Author:   (), 
 *        Company:  
 *
 * ===========================================================================
 */

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<netdb.h>
#include<sys/socket.h>
#include<memory.h>

void out_host(struct hostent *h){
  //獲取主機名稱
  char *host_name = h->h_name;
  printf("host_name:%s\n",host_name);

  //獲取網路型別
  int host_addrtype = h->h_addrtype;
  if(host_addrtype == AF_INET){
    printf("addrtype:IPV4\n");
  }else{
    printf("addrtype:IPV6\n");
  }
  //獲取主機網路地址的大小
  int host_length = h->h_length;
  printf("host_length:%d\n",host_length);

  //獲取主機的ip,主機的ip對應的是網路地址陣列中的0,記住要將網路位元組序轉換成主機位元組序號
  char ip[16];
  memset(ip,0,sizeof(ip));
  inet_ntop(h->h_addrtype,h->h_addr_list[0],ip,sizeof(ip));
  printf("host ip:%s\n",ip);

  //遍歷去獲取別名
  int aliase_count = 0;
  while( h->h_aliases[aliase_count] != NULL){
    printf("host_aliases[%d]:%s\n",aliase_count,h->h_aliases[aliase_count]);
    aliase_count++;
 }
  int host_addr_list_count = 0;
  while(h->h_addr_list[host_addr_list_count] != NULL){
    memset(ip,0,sizeof(ip));
    inet_ntop(h->h_addrtype,h->h_addr_list[host_addr_list_count],ip,sizeof(ip));
    printf("host_addr_list[%d]:%s\n",host_addr_list_count,ip);
    host_addr_list_count++;
  }
}


int main(int argc,char *argv[]){
  if(argc < 2){
    printf("usage: %s host\n",argv[0]);
    exit(EXIT_FAILURE);
  }

  struct hostent *h;

  //因為gethost返回的是一個結構體陣列
  while((h = gethostent()) != NULL){
    if(strcmp(argv[1],h->h_name) == 0){
      out_host(h);
    }else{
      int aliases_count = 0;
      while(h->h_aliases[aliases_count] != NULL){
          if(strcmp(argv[1],h->h_aliases[aliases_count]) == 0){
             out_host(h);
             exit(EXIT_FAILURE);
          }
          aliases_count++;
      }

    }
  }

 endhostent(); 

  return 0;
}

以上除了虛擬碼部分,gethostbyname.c個gethostent.c的程式碼都是直接可以進行run的,在使用的時候相對來說是比較推薦去使用gethostent的,因為gethostbyname不支援ipv6以及不建議在多執行緒情況下去使用的.當然,這也只是簡單的去了解下dns去在解析的時候的簡單的原理.