2013-01-07 94 views
1

用C語言編寫的我的FTP程序僅在服務器地址是IP地址時才起作用。但是,當服務器地址是完全限定域名(FQDN)時,連接將失敗。 當ftp_host是FQDN時,ftp連接無法打開。請幫忙。服務器地址爲FQDN時無法打開FTP連接

回答

3

我強烈建議使用getaddrinfo()函數,如gethostbyname() is obsolete。這也有一個好處,無論是現在還是以後,很容易轉換爲IPv6。

我假設你只關心IPv4地址,所以這裏是一個函數的例子,將採取主機名作爲參數,並在struct sockaddr_in爲您填寫:

int get_ftp_addr(const char *hostname, struct sockaddr_in *addr) 
{ 
    char host_buffer[256]; 
    struct addrinfo hints; 
    struct addrinfo *result; 
    struct sockaddr_in *res_addr; 
    int error = -1; 
    char *colon; 

    snprintf(host_buffer, sizeof(host_buffer), "%s", hostname); 

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

    colon = strchr(host_buffer, ':'); 
    if (colon) { 
    *colon = '\0'; 
    error = getaddrinfo(host_buffer, colon + 1, &hints, &result); 
    } else { 
    error = getaddrinfo(host_buffer, "ftp", &hints, &result); 
    } 

    if (error != 0 || !result) { 
    return error; 
    } 

    res_addr = (struct sockaddr_in*)(result->ai_addr); 
    memcpy(addr, res_addr, sizeof(struct sockaddr_in)); 

    freeaddrinfo(result); 
    return 0; 
} 

請注意,我只取一個字符串的副本,以避免修改調用者的版本 - 如果你不想要,不要覺得有必要保留這個部分,但是我個人認爲它是一個更清晰的接口。

該功能將接受以點分四分法表示法和完全限定主機名的IP地址,因爲getaddrinfo()接受這兩個IP地址。如果使用冒號指定端口,則將使用端口,否則將使用默認FTP端口。

零返回值表示成功。一個正返回值可以傳入gai_strerror()以獲取字符串錯誤代碼,或者您可以檢查getaddrinfo() man page以獲取可能的錯誤代碼。 -1的返回值表示從getaddrinfo()獲得的成功結果,但沒有結果結構 - 我不認爲這可能發生,但我不想讓任何可能的返回代碼未處理。

有幾個注意事項這裏,兩個最重要的是:

  • 此代碼只支持IPv4的樣子,雖然getaddrinfo()使得它很容易支持IPv6,以及。如果你想支持兩者,那麼將提示結構中的AF_INET更改爲AF_UNSPEC,您將獲得所有地址系列。不過,你需要迭代地址,並且只篩選出IPv4和IPv6地址(參見我的下一個要點)。
  • DNS查找可能會查找多個IP地址 - 這對於大型站點(如Google)來說很常見,因爲他們使用此功能在主機間進行負載平衡,並且還有冗餘。理想情況下,你的代碼應該遍歷所有返回的地址,並嘗試連接到每一個,直到一個工程。對於FTP客戶端來說,這可能是矯枉過正的,但我認爲了解它是很重要的。

如果要支持IPv6,或支持多A記錄(即多個地址從DNS查詢後),那麼你需要遵循struct addrinfo結構ai_next指針 - 是這樣的:

struct addrinfo *res; 

/* Assume result is initialised as above via getaddrinfo() */ 

for (res = result; res != NULL; res = res->ai_next) { 
    ... 
}