2012-07-20 39 views
8

Beej's Simple Client示例代碼遍歷從getaddrinfo()返回的所有IP地址,直到它可以連接到第一個。請參閱下面的代碼。是否需要嘗試連接到由getaddrinfo()返回的所有地址?

這是否總是必要的,或者可以假設我們只需要嘗試連接getaddrinfo()返回的第一個地址?

memset(&hints, 0, sizeof hints); 
hints.ai_family = AF_UNSPEC; 
hints.ai_socktype = SOCK_STREAM; 

if ((rv = getaddrinfo(argv[1], PORT, &hints, &servinfo)) != 0) { 
    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); 
    return 1; 
} 

// ------------------------------------------------------------ 
// loop through all the results and connect to the first we can 
for(p = servinfo; p != NULL; p = p->ai_next) { 
    if ((sockfd = socket(p->ai_family, p->ai_socktype, 
      p->ai_protocol)) == -1) { 
     perror("client: socket"); 
     continue; 
    } 

    if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) { 
     close(sockfd); 
     perror("client: connect"); 
     continue; 
    } 

    break; 
} 

回答

9

是的,您應該遍歷所有地址 - 特別是考慮目標主機啓用IPv6地址但本地主機不啓用的情況。 getaddrinfo()將返回AF_INET6家庭地址,但然後socket()connect()調用將失敗。

這也是您的主機支持實現多種協議的可能性SOCK_STREAM(比方說,除了TCP SCTP)和目標主機不 - 因爲你還沒有設置提示結構的ai_protocol成員,地址代表所有協議支持SOCK_STREAM套接字將被退回。

0

假設你剛接觸socket,在這一點上。是的,這很關鍵,因爲在使用getaddrinfo之後,您可以檢索地址信息以進一步驗證。

2

讓我們來看看這種方式......你想連接的服務器主機可能有幾個地址與之關聯,但實際的服務器程序只能監聽其中一個地址。如果您的客戶端不知道服務器程序正在偵聽的確切地址,則必須嘗試主機所具有的所有地址,直到找到正確的地址並且可以連接。

+0

實際上,爲什麼主機可能有多個地址?最明顯的用途是冗餘。如果第一臺主機沒有響應,你可能會獲得更好的成功,如果你走的清單... – asveikau 2012-07-20 05:56:47

+0

@asveikau主機有多個地址的實際原因可能會有所不同。這可能是因爲冗餘,或者它可能是服務於兩個不同的網絡,或許多其他原因。 – 2012-07-20 06:04:14

+0

冗餘或負載平衡。 – Lothar 2014-03-23 15:57:11

1

是的,你應該循環所有這些 - 不保證第一個(或者你選擇的)地址實際上是有效的。這就是爲什麼在教程中這樣做的原因。

4

除了上面給出的其他答案之外,考慮一個常見的情況,即爲了冗餘目的,對於大型網站等,可能會發布多個A記錄。如果第一個地址的connect()失敗,您也想嘗試其他地址。

相關問題