【问题标题】:Cannot open FTP connection when server address is FQDN服务器地址为 FQDN 时无法打开 FTP 连接
【发布时间】:2013-01-07 18:24:30
【问题描述】:

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

【问题讨论】:

    标签: c sockets networking ftp


    【解决方案1】:

    我强烈建议使用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() 的成功结果,但没有结果结构 - 我认为这不会发生,但我不喜欢留下任何可能的返回码未处理。

    这里有几个注意事项,其中两个最重要的是:

    • 此代码仅支持 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) {
        ...
    }
    

    【讨论】:

      猜你喜欢
      • 2010-12-01
      • 2011-10-04
      • 1970-01-01
      • 2011-05-28
      • 2017-11-11
      • 2021-02-03
      • 1970-01-01
      • 1970-01-01
      • 2013-02-12
      相关资源
      最近更新 更多