1

Cで記述されたFTPプログラムは、サーバーアドレスがIPアドレスの場合にのみ機能します。ただし、サーバーアドレスが完全修飾ドメイン名(FQDN)の場合、接続は失敗します。ftp_hostがFQDNの場合、ftp接続を開くことができません。助けてください。

4

1 に答える 1

3

gethostbyname()は廃止getaddrinfo()されたため、この関数を使用することを強くお勧めします。これには、現在または後で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()のマニュアルページで考えられるエラーコードを確認できます。の戻り値は、結果の構造が-1成功してgetaddrinfo()いないことを示します。これが発生する可能性はないと思いますが、可能な戻りコードを未処理のままにしておくのは好きではありません。

ここにはいくつかの注意点がありますが、最も重要な2つは次のとおりです。

  • このコードは、getaddrinfo()IPv6のサポートも非常に簡単ですが、現状ではIPv4のみをサポートしています。両方をサポートする場合AF_INETは、ヒント構造のをに変更すると、AF_UNSPECすべてのアドレスファミリが取得されます。ただし、アドレスを反復処理し、IPv4とIPv6のアドレスのみを除外する必要があります(次のポイントを参照)。
  • DNSルックアップは、複数のIPアドレスをルックアップする可能性があります。これは、ホスト間の負荷分散と冗長性のためにこの機能を使用するため、Googleなどの大規模サイトでは非常に一般的です。理想的には、返されたすべてのアドレスを反復処理し、1つが機能するまで各アドレスに接続してみてください。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 に答える