1

我用 C 语言编写的 FTP 程序仅在服务器地址为 IP 地址时才有效。但是,当服务器地址是完全限定域名 (FQDN) 时,连接会失败。当 ftp_host 为 FQDN 时,ftp 连接无法打开。请帮忙。

4

1 回答 1

3

我强烈建议使用该getaddrinfo()函数,因为gethostbyname() 已过时。这还有一个优点,即现在或以后都可以轻松转换为 IPv6。

我假设您只关心 IPv4 地址,所以这里有一个函数示例,它将以主机名作为其参数并struct sockaddr_in为您填写 a:

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() 手册页以获取可能的错误代码。返回-1表示来自结果结构的成功结果,getaddrinfo()但没有结果结构 - 我认为这不会发生,但我不喜欢留下任何可能的返回代码未处理。

这里有几个警告,其中两个最重要的是:

  • 这段代码只支持 IPv4,尽管getaddrinfo()它也很容易支持 IPv6。如果您想同时支持两者AF_INET,则将提示结构中的 更改为AF_UNSPEC,您将获得所有地址族。不过,您需要遍历地址,并仅过滤掉 IPv4 和 IPv6 的地址(请参阅我的下一点)。
  • DNS 查找可能会查找多个 IP 地址——这在 Google 等大型站点中很常见,因为它们使用此功能来实现跨主机的负载平衡以及冗余。理想情况下,您的代码应该遍历所有返回的地址,并尝试连接到每个地址,直到一个有效。对于 FTP 客户端来说,这可能有点矫枉过正,但我​​认为意识到这一点很重要。

如果您想支持 IPv6,或支持多 A 记录(即从 DNS 查询返回的多个地址),那么您需要遵循结构ai_next中的指针struct addrinfo- 如下所示:

struct addrinfo *res;

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

for (res = result; res != NULL; res = res->ai_next) {
    ...
}
于 2013-01-08T15:25:24.197 回答