【发布时间】:2013-01-07 18:24:30
【问题描述】:
我用 C 语言编写的 FTP 程序只有在服务器地址是 IP 地址时才能工作。但是,当服务器地址是完全限定域名 (FQDN) 时,连接会失败。 当 ftp_host 为 FQDN 时,ftp 连接无法打开。请帮忙。
【问题讨论】:
标签: c sockets networking ftp
我用 C 语言编写的 FTP 程序只有在服务器地址是 IP 地址时才能工作。但是,当服务器地址是完全限定域名 (FQDN) 时,连接会失败。 当 ftp_host 为 FQDN 时,ftp 连接无法打开。请帮忙。
【问题讨论】:
标签: c sockets networking ftp
我强烈建议使用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() 接受这两者。如果使用冒号指定端口,则使用该端口,否则使用默认 FTP 端口。
返回值为零表示成功。可以将正返回传递给gai_strerror() 以获取字符串错误代码,或者您可以检查getaddrinfo() man page 以获取可能的错误代码。 -1 的返回表示来自 getaddrinfo() 的成功结果,但没有结果结构 - 我认为这不会发生,但我不喜欢留下任何可能的返回码未处理。
这里有几个注意事项,其中两个最重要的是:
getaddrinfo() 也使支持 IPv6 变得非常容易。如果您想同时支持两者,请将提示结构中的AF_INET 更改为AF_UNSPEC,您将获得所有地址系列。不过,您需要遍历地址,并仅过滤掉 IPv4 和 IPv6 的地址(请参阅我的下一点)。如果你想支持 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) {
...
}
【讨论】: