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