# 網絡,第 2 部分:使用 getaddrinfo
> 原文:<https://github.com/angrave/SystemProgramming/wiki/Networking%2C-Part-2%3A-Using-getaddrinfo>
## 如何使用`getaddrinfo`將主機名轉換為 IP 地址?
函數`getaddrinfo`可以將人類可讀域名(例如`www.illinois.edu`)轉換為 IPv4 和 IPv6 地址。實際上它將返回 addrinfo 結構的鏈表:
```c
struct addrinfo {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
socklen_t ai_addrlen;
struct sockaddr *ai_addr;
char *ai_canonname;
struct addrinfo *ai_next;
};
```
它非常易于使用。例如,假設您想在 [www.bbc.com](http://www.bbc.com) 中找到網絡服務器的數字 IPv4 地址。我們分兩個階段完成。首先使用 getaddrinfo 構建可能的連接的鏈表。其次使用`getnameinfo`將二進制地址轉換為可讀形式。
```c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
struct addrinfo hints, *infoptr; // So no need to use memset global variables
int main() {
hints.ai_family = AF_INET; // AF_INET means IPv4 only addresses
int result = getaddrinfo("www.bbc.com", NULL, &hints, &infoptr);
if (result) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(result));
exit(1);
}
struct addrinfo *p;
char host[256],service[256];
for(p = infoptr; p != NULL; p = p->ai_next) {
getnameinfo(p->ai_addr, p->ai_addrlen, host, sizeof(host), service, sizeof(service), NI_NUMERICHOST);
puts(host);
}
freeaddrinfo(infoptr);
return 0;
}
```
典型輸出:
```
212.58.244.70
212.58.244.71
```
## [www.cs.illinois.edu](http://www.cs.illinois.edu) 如何轉換為 IP 地址?
魔法!不用說,使用稱為“DNS”(域名服務)的系統。如果計算機沒有在本地保存答案,則它會將 UDP 數據包發送到本地 DNS 服務器。該服務器又可以查詢其他上游 DNS 服務器。
## DNS 安全嗎?
DNS 本身很快但不安全。 DNS 請求未加密,容易受到“中間人”攻擊。例如,咖啡店互聯網連接可以輕易地破壞您的 DNS 請求并發回特定域的不同 IP 地址
## 如何連接到 TCP 服務器(例如 Web 服務器?)
TODO 連接到遠程計算機需要三個基本系統調用:
```
getaddrinfo -- Determine the remote addresses of a remote host
socket -- Create a socket
connect -- Connect to the remote host using the socket and address information
```
`getaddrinfo`調用成功,創建`addrinfo`結構的鏈接列表,并將給定指針設置為指向第一個。
套接字調用創建一個傳出套接字并返回一個描述符(有時稱為“文件描述符”),可以與`read`和`write`等一起使用。在這種意義上,它是`open`的網絡模擬打開文件流 - 除了我們尚未將套接字連接到任何東西!
最后,connect 調用嘗試連接到遠程計算機。我們傳遞原始套接字描述符以及存儲在 addrinfo 結構中的套接字地址信息。存在不同種類的套接字地址結構(例如,IPv4 與 IPv6),其可能需要更多存儲器。因此,除了傳遞指針外,還傳遞了結構的大小:
```c
// Pull out the socket address info from the addrinfo struct:
connect(sockfd, p->ai_addr, p->ai_addrlen)
```
## 如何釋放為 addrinfo 結構的鏈表分配的內存?
作為最頂層`addrinfo`結構上的清理代碼調用`freeaddrinfo`的一部分:
```c
void freeaddrinfo(struct addrinfo *ai);
```
## 如果 getaddrinfo 失敗,我可以用`strerror`打印出錯誤嗎?
沒有。`getaddrinfo`的錯誤處理有點不同:
* 返回值 _ 是 _ 的錯誤代碼(即不使用`errno`)
* 使用`gai_strerror`獲取等效的短英文錯誤文本:
```c
int result = getaddrinfo(...);
if(result) {
const char *mesg = gai_strerror(result);
...
}
```
## 我可以只請求 IPv4 或 IPv6 連接嗎?僅 TCP?
是!使用傳遞給`getaddrinfo`的 addrinfo 結構來定義您想要的連接類型。
例如,要通過 IPv6 指定基于流的協議:
```c
struct addrinfo hints;
memset(hints, 0, sizeof(hints));
hints.ai_family = AF_INET6; // Only want IPv6 (use AF_INET for IPv4)
hints.ai_socktype = SOCK_STREAM; // Only want stream-based connection
```
## 那些使用`gethostbyname`的代碼示例呢?
舊函數`gethostbyname`已棄用;這是將主機名轉換為 IP 地址的舊方法。端口地址仍需要使用 htons 功能手動設置。使用較新的`getaddrinfo`編寫支持 IPv4 和 IPv6 的代碼要容易得多
## 這很容易!?
是的,不是。創建一個簡單的 TCP 客戶端很容易 - 但網絡通信提供了許多不同的抽象級別,并且可以在每個抽象級別設置幾個屬性和選項(例如我們沒有談到可以操作選項的`setsockopt`插座)。有關詳細信息,請參閱[指南](http://www.beej.us/guide/bgnet/output/html/multipage/getaddrinfoman.html)。
- UIUC CS241 系統編程中文講義
- 0. 簡介
- #Informal 詞匯表
- #Piazza:何時以及如何尋求幫助
- 編程技巧,第 1 部分
- 系統編程短篇小說和歌曲
- 1.學習 C
- C 編程,第 1 部分:簡介
- C 編程,第 2 部分:文本輸入和輸出
- C 編程,第 3 部分:常見問題
- C 編程,第 4 部分:字符串和結構
- C 編程,第 5 部分:調試
- C 編程,復習題
- 2.進程
- 進程,第 1 部分:簡介
- 分叉,第 1 部分:簡介
- 分叉,第 2 部分:Fork,Exec,等等
- 進程控制,第 1 部分:使用信號等待宏
- 進程復習題
- 3.內存和分配器
- 內存,第 1 部分:堆內存簡介
- 內存,第 2 部分:實現內存分配器
- 內存,第 3 部分:粉碎堆棧示例
- 內存復習題
- 4.介紹 Pthreads
- Pthreads,第 1 部分:簡介
- Pthreads,第 2 部分:實踐中的用法
- Pthreads,第 3 部分:并行問題(獎金)
- Pthread 復習題
- 5.同步
- 同步,第 1 部分:互斥鎖
- 同步,第 2 部分:計算信號量
- 同步,第 3 部分:使用互斥鎖和信號量
- 同步,第 4 部分:臨界區問題
- 同步,第 5 部分:條件變量
- 同步,第 6 部分:實現障礙
- 同步,第 7 部分:讀者編寫器問題
- 同步,第 8 部分:環形緩沖區示例
- 同步復習題
- 6.死鎖
- 死鎖,第 1 部分:資源分配圖
- 死鎖,第 2 部分:死鎖條件
- 死鎖,第 3 部分:餐飲哲學家
- 死鎖復習題
- 7.進程間通信&amp;調度
- 虛擬內存,第 1 部分:虛擬內存簡介
- 管道,第 1 部分:管道介紹
- 管道,第 2 部分:管道編程秘密
- 文件,第 1 部分:使用文件
- 調度,第 1 部分:調度過程
- 調度,第 2 部分:調度過程:算法
- IPC 復習題
- 8.網絡
- POSIX,第 1 部分:錯誤處理
- 網絡,第 1 部分:簡介
- 網絡,第 2 部分:使用 getaddrinfo
- 網絡,第 3 部分:構建一個簡單的 TCP 客戶端
- 網絡,第 4 部分:構建一個簡單的 TCP 服務器
- 網絡,第 5 部分:關閉端口,重用端口和其他技巧
- 網絡,第 6 部分:創建 UDP 服務器
- 網絡,第 7 部分:非阻塞 I O,select()和 epoll
- RPC,第 1 部分:遠程過程調用簡介
- 網絡復習題
- 9.文件系統
- 文件系統,第 1 部分:簡介
- 文件系統,第 2 部分:文件是 inode(其他一切只是數據...)
- 文件系統,第 3 部分:權限
- 文件系統,第 4 部分:使用目錄
- 文件系統,第 5 部分:虛擬文件系統
- 文件系統,第 6 部分:內存映射文件和共享內存
- 文件系統,第 7 部分:可擴展且可靠的文件系統
- 文件系統,第 8 部分:從 Android 設備中刪除預裝的惡意軟件
- 文件系統,第 9 部分:磁盤塊示例
- 文件系統復習題
- 10.信號
- 過程控制,第 1 部分:使用信號等待宏
- 信號,第 2 部分:待處理的信號和信號掩碼
- 信號,第 3 部分:提高信號
- 信號,第 4 部分:信號
- 信號復習題
- 考試練習題
- 考試主題
- C 編程:復習題
- 多線程編程:復習題
- 同步概念:復習題
- 記憶:復習題
- 管道:復習題
- 文件系統:復習題
- 網絡:復習題
- 信號:復習題
- 系統編程笑話