自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

編程實(shí)戰(zhàn):如何在程序中解析域名

網(wǎng)絡(luò) 通信技術(shù)
網(wǎng)絡(luò)應(yīng)用客戶端想要跟服務(wù)端通信,必須先向 DNS 服務(wù)器查詢域名對(duì)應(yīng)的 IP 地址。舉個(gè)例子,讀者訪問(wèn)我的網(wǎng)站 fasionchan.com 時(shí),瀏覽器需要先根據(jù)域名查詢網(wǎng)站的 IP 地址,再和網(wǎng)站的 Web 服務(wù)器進(jìn)行通信。

[[403061]]

本文轉(zhuǎn)載自微信公眾號(hào)「小菜學(xué)編程」,作者fasionchan。轉(zhuǎn)載本文請(qǐng)聯(lián)系小菜學(xué)編程公眾號(hào)。

由于域名比 IP 地址更便于記憶,我們通常使用它來(lái)訪問(wèn)網(wǎng)絡(luò)服務(wù)。

網(wǎng)絡(luò)應(yīng)用客戶端想要跟服務(wù)端通信,必須先向 DNS 服務(wù)器查詢域名對(duì)應(yīng)的 IP 地址。舉個(gè)例子,讀者訪問(wèn)我的網(wǎng)站 fasionchan.com 時(shí),瀏覽器需要先根據(jù)域名查詢網(wǎng)站的 IP 地址,再和網(wǎng)站的 Web 服務(wù)器進(jìn)行通信。

那么,如何通過(guò)編程實(shí)現(xiàn)域名查詢呢?這是開發(fā)網(wǎng)絡(luò)應(yīng)用無(wú)法回避的問(wèn)題。

我們知道,DNS 服務(wù)器和客戶端之間使用 DNS 協(xié)議進(jìn)行通信:客戶端先向服務(wù)器發(fā)送 請(qǐng)求報(bào)文 ,服務(wù)器將查詢結(jié)果封裝成 應(yīng)答報(bào)文 ,回復(fù)客戶端。DNS 可以使用 UDP 或 TCP 作為傳輸層協(xié)議,通信端口號(hào)為 53 。

假設(shè)客戶端使用 UDP 協(xié)議,一次域名查詢的步驟大致如下:

  1. 創(chuàng)建一個(gè) UDP 套接字;
  2. 封裝 DNS 請(qǐng)求報(bào)文,待查詢域名位于問(wèn)題節(jié);
  3. 通過(guò) UDP 套接字,將請(qǐng)求報(bào)文發(fā)給 DNS 服務(wù)器(服務(wù)端端口一般是 53 );
  4. 等待服務(wù)端響應(yīng),并從 UDP 套接字讀取應(yīng)答報(bào)文;
  5. 解析應(yīng)答報(bào)文,獲得查詢結(jié)果;
  6. 關(guān)閉 UDP 套接字;

如果每個(gè)網(wǎng)絡(luò)應(yīng)用都需要自行封裝 DNS 報(bào)文實(shí)現(xiàn)域名查詢,未免太麻煩了!為此,C庫(kù)提供了一系列工具函數(shù)。應(yīng)用程序只需調(diào)用這些工具函數(shù),即可完成域名查詢,不用自己操作套接字,或者封裝 DNS 報(bào)文。

示例程序

這個(gè)程序調(diào)用 C 庫(kù)函數(shù) gethostbyname ,將用戶在命令行參數(shù)中指定的域名查詢出來(lái):

  1. #include <arpa/inet.h> 
  2. #include <netdb.h> 
  3. #include <stdio.h> 
  4.  
  5. int main(int argc, char *argv[]) { 
  6.     if (argc != 2) { 
  7.         fprintf(stderr, "bad arguments"); 
  8.         return -1; 
  9.     } 
  10.  
  11.     char *name = argv[1]; 
  12.     printf("resolve domain name: %s\n"name); 
  13.  
  14.     struct hostent *result = gethostbyname(name); 
  15.     if (result == NULL) { 
  16.         if (h_errno == HOST_NOT_FOUND) { 
  17.             fprintf(stderr, "Hostname not found!\n"); 
  18.         } 
  19.  
  20.         if (h_errno == NO_DATA) { 
  21.             fprintf(stderr, "No such record\n"); 
  22.         } 
  23.  
  24.         if (h_errno == NO_RECOVERY) { 
  25.             fprintf(stderr, "\n"); 
  26.         } 
  27.  
  28.         if (h_errno == TRY_AGAIN) { 
  29.             fprintf(stderr, "Temporary error occurred, please try again!\n"); 
  30.         } 
  31.  
  32.         return -1; 
  33.     } 
  34.  
  35.     int i = 0; 
  36.     while (result->h_addr_list[i] != NULL) { 
  37.         printf("IP: %s\n", inet_ntoa(*(struct in_addr *)result->h_addr_list[i])); 
  38.         i++; 
  39.     } 
  40.  
  41.     return 0; 

顧名思義,gethostbyname 根據(jù)域名查詢主機(jī)的地址,結(jié)果一般是 IP 地址或者 IPv6 地址。

請(qǐng)看程序第 14 行,以待查詢域名為參數(shù)調(diào)用 gethostbyname 函數(shù);它返回一個(gè) hostent 結(jié)構(gòu)體指針,結(jié)構(gòu)體中保存著域名查詢結(jié)果。

第 15-33 行,檢查域名解析結(jié)果,空表示出錯(cuò);出錯(cuò)時(shí)根據(jù) h_errno 的值,分情況處理(詳情請(qǐng)見后文)。

第 35-39 行,從 hostent 結(jié)構(gòu)體中取出查詢結(jié)果,并打印到屏幕上。

那么, gethostbyname 庫(kù)函數(shù)內(nèi)部都做了些什么呢?答案其實(shí)不難猜到。它會(huì)幫我們創(chuàng)建 UDP 套接字、發(fā)送 DNS 請(qǐng)求報(bào)文、接收并解析應(yīng)答報(bào)文。以這個(gè)程序?yàn)槔?,它的?zhí)行流(藍(lán)線)大致如下:

域名查詢庫(kù)函數(shù)

實(shí)際上,C 庫(kù)提供了一系列工具函數(shù),用于域名查詢:

  • gethostbyname ,查詢指定域名,查詢結(jié)果保存在 hostent 結(jié)構(gòu)體中,指針被返回給調(diào)用者;
  • gethostbyname_r ,同上,為線程安全版本,可在多線程環(huán)境中使用;
  • gethostbyname2 ,同一,但支持通過(guò) af 參數(shù)指定查詢地址類型;
  • gethostbyname2_r ,同三,為線程安全版本,可在多線程環(huán)境中使用;

以 gethostbyname 為例,如果查詢成功,它將返回一個(gè) hostent 結(jié)構(gòu)體指針,結(jié)構(gòu)體保存著查詢結(jié)果。如果查詢出錯(cuò),它將返回 NULL ,并將錯(cuò)誤保存 h_errno 全局變量。一般而言,域名查詢出錯(cuò),可以分為這幾種情況:

HOST_NOT_FOUND ,表示指定主機(jī)不存在,即域名不存在;

NO_DATA ,表示域名存在其他記錄,但沒(méi)有地址相關(guān)記錄( A 或者 AAAA );

NO_RECOVERY ,域名服務(wù)器出現(xiàn)不可恢復(fù)錯(cuò)誤;

TRY_AGAIN ,臨時(shí)出錯(cuò),可通過(guò)重試恢復(fù);

當(dāng)域名查詢失敗時(shí),調(diào)用者必須檢查 h_errno 變量,分情況進(jìn)行處理。

局限性

在網(wǎng)絡(luò)爬蟲、Socks5 代理等應(yīng)用場(chǎng)景,域名查詢非常頻繁。這時(shí)直接使用 gethostbyname 系列庫(kù)函數(shù),很有可能會(huì)面臨性能瓶頸。

一方面,gethostbyname 庫(kù)函數(shù)每次查詢域名時(shí),都要?jiǎng)?chuàng)建一個(gè) UDP 套接字來(lái)跟 DNS 服務(wù)器通信。這意味著,頻繁的域名查詢背后,必然伴隨著大量套接字的創(chuàng)建和銷毀,開銷可想而知!

另一方面,gethostbyname 庫(kù)函數(shù)將一直阻塞,直到 DNS 服務(wù)器返回結(jié)果或者查詢超時(shí)。這將嚴(yán)重制約系統(tǒng)的并發(fā)處理能力。

因此,在高頻查詢場(chǎng)景,不能直接使用 gethostbyname 等庫(kù)函數(shù),必須采用一些經(jīng)過(guò)優(yōu)化的異步域名解析庫(kù)。

擴(kuò)展閱讀

 

gethostbyname

 

責(zé)任編輯:武曉燕 來(lái)源: 小菜學(xué)編程
相關(guān)推薦

2021-09-16 17:38:49

UbuntuLinuxJava

2009-06-08 21:35:02

Java啟動(dòng)程序

2021-09-13 09:01:02

Vue 技巧 開發(fā)工具

2023-12-28 10:30:56

類型系統(tǒng)Rust

2023-09-27 23:24:50

C++鏈表

2018-12-29 09:45:28

Linux編程語(yǔ)言命令

2016-07-29 11:21:16

Ubuntulinux程序

2014-05-28 09:45:55

CentOS域名服務(wù)器

2018-10-29 10:13:29

Windows 10應(yīng)用程序卸載

2019-03-27 13:20:31

Windows 10更新驅(qū)動(dòng)程序

2021-08-30 07:50:42

腳本語(yǔ)言命令行

2018-06-05 08:51:04

Linux結(jié)束進(jìn)程中止程序

2021-09-14 12:34:33

LinuxLinux終端

2018-08-27 14:50:46

LinuxShellBash

2010-05-20 17:52:02

2022-04-01 07:35:45

IDEAJavaWeb 項(xiàng)目

2024-08-13 08:27:24

PythonTCP協(xié)議網(wǎng)絡(luò)編程

2024-01-15 07:15:05

函數(shù)式編程代碼

2019-05-08 11:30:41

MicrosoftWindows 10后臺(tái)應(yīng)用程序

2018-07-18 16:35:06

Windows 10Windows驅(qū)動(dòng)程序
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)