2013-01-07 69 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) { 
    ... 
}