ドメインネームシステム
ここでは、コンピューター ネットワークの初心者向けに、インターネットをサーフィンするときに www.baidu.com に似たドメイン名を使用するドメイン名システムについて簡単に説明します。つまり、IP アドレスとドメイン名を同時に使用して Web サイトにアクセスできますが、この 2 つの違いは何でしょうか? 実際、ドメイン名は実際のアドレスではなく、IP アドレスの仮想アドレスであると理解できます。したがって、仮想アドレスを実アドレスに変換する必要がある。この変換の重要なタスクは、DNS サーバーに対するものです。
各コンピュータにはデフォルトの DNS サーバーがあります。コンピュータが特定のドメイン名に対応する IP アドレスを問い合わせたい場合、まずデフォルトの DNS サーバーに問い合わせリクエストを送信します。DNS サーバーが特定のドメイン名に対応する IP アドレスを知らない場合は、上位の DNS サーバーに問い合わせます。最上位の DNS サーバーに到達すると、どの DNS にリクエストを送信するかを確実に認識します。その後、解決要求は下位の DNS に渡され、IP アドレスを取得した後、元のパスが再帰的に返されます。最後に、コンピュータはターゲット ドメイン名の IP アドレスを知ることができます。
プログラム内でドメイン名を使用する必要がありますか?
この質問は、この章を研究する理由の答えになります。企業が提供するサービスを使用するためのクライアントを開発しているシナリオを想像してください。したがって、会社のサービスを利用したい場合は、会社のサーバーにアクセスする必要があります。では、サーバーのドメイン名またはサーバー アドレスはクライアント内に保存されているのでしょうか? システムの稼働中に IP アドレスを維持するのは容易ではなく、システムに関連するさまざまな理由により IP アドレスが変更されることがあります。この変更により、ソース コード内の IP アドレスを常に変更する必要がありますが、専門知識のないユーザーにとっては現実的ではありません。
ドメイン名は一度登録すると永続的なものになる可能性があるため、プログラムを作成する際にはドメイン名を使用することをお勧めします。このように、プログラムの実行時にドメイン名に基づいて IP アドレスが取得され、サーバーに接続されるため、プログラムはサーバーの IP アドレスに依存しません。したがって、プログラムにはIPアドレスとドメイン名の変換機能も必要になります。
ドメイン名を使用して IP アドレスを取得する
次の関数を使用すると、ドメイン名を文字列形式で渡すことで IP アドレスを取得できます。
#include<netdb.h>
struct hostnet * gethostbyname(const char*hostname);
//成功时返回houstnet结构体地址,失败时返回NULL指针
まず、次の構造定義を導入します。
struct hostent{
char * h_name; //official name
char ** h_aliases; //alias list
int h_addrtype; //host address type
int h_length; //address length
char ** h_addr _list; //address list
}
h_name
この変数には、正式なドメイン名 (正式なドメイン名) が含まれます。正式ドメイン名はあるホームページを表しますが、実は
一部の有名企業のドメイン名は正式ドメイン名に登録されていません。
h_aliases は、
複数のドメイン名を介して同じホームページにアクセスできます。複数のドメイン名を同じ IP にバインドできるため、
正式なドメイン名に加えて他のドメイン名を指定できます。この情報は、h_aliases を通じて取得できます。
h_addrtype
gethostbyname 関数は、IPv4 だけでなく、IPv6 もサポートします。したがって、h_addr_list に格納されている IP アドレスのアドレスファミリー情報は、この変数を通じて取得できます。IPv4 の場合、この変数には AF_INET が保持されます。
h_length は
IP アドレスの長さを保存します。IPv4 アドレスの場合は 4 バイトなので 4 を節約し、IPv6 の場合は 16 バイトであるため 16 を節約します。
h_addr_list
最も重要なメンバーです。この変数を使用して、ドメイン名に対応する IP アドレスを整数形式で保存します。さらに、多くのユーザーがいる Web サイトでは、同じドメイン名に複数の IP が割り当てられ、負荷分散のために複数のサーバーが使用される場合があります。このとき、この変数を通じてアドレス情報も取得できます。
以下に示す例を示します。
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<netdb.h>
void error_handling(char* message);
int main(int argc,char*argv[]){
int i;
struct hostent *host;
if(argc!=2){
printf("Usage : %s <addr>\n",argv[0]);
exit(1);
}
host=gethostbyname(argv[1]);
if(!host)error_handling("gethost...error");
printf("Official name: %s \n",host->name);
for(int i=0;host->h_aliases[i];i++)printf("Aliases %d: %s\n",i+1,host->aliases[i]);
printf("Address type: %s\n",(host->h_addrtype==AF_INET)?"AF_INET":"AF_INET6");
for(int i=0;host->h_addr_list[i];i++)
printf("IP addr %d: %s \n",i+1,inet_ntoa(*(struct in_addr*)host->h_addr_list[i]));
return 0;
}
voie error_handling(char *message){
fputs(message,stderr);
fputc('\n',stderr);
exit(1);
}
次に、上記の例の 26 ~ 28 行目を説明します。hostent 構造体の定義だけを見ると、構造体メンバー h_addr_list は文字列ポインターの配列を指しています。ただし、文字列ポインター配列内の要素は、実際には文字列ではなく in_addr 構造体変数のアドレス値を指します。
IPアドレスを使用してドメイン名を取得する
#include<netdb.h>
struct hostent *gethostbyaddr(const char* addr,socklen_t len,int family);
//成功时返回hostent结构体变量地址,失败时返回NULL指针
addr //含有IP地址信息的in_addr结构体指针。为了同时传递IPv4地址以外的其他信息,该变量声明为char指针
len //第一个参数传递的地址信息的字节数
family //传递的地址族信息
次の例は、この関数の使用方法を示しています。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>
void error_handling(char *message);
int main(int argc, char *argv[]){
int i;
struct hostent *host;
struct sockaddr_in addr;
if(argc!=2){
printf("Usage : %s <IP>\n", argv[0]);
exit(1);
}
memset(&addr, 0, sizeof(addr));
addr.sin_addr.s_addr=inet_addr(argv[1]);
host=gethostbyaddr((char*)&addr.sin_addr,4, AF_INET);
if(!host)error handling("gethost... error");
printf("Official name: %s \n", host->h_name);
for(i=0; host->h_aliases[i]; i++)printf("Aliases %d: %s \n", i+1, host->h_aliases[i]);
printf("Address type: %s \n",(host->h_addrtype==AF_INET)?"AF_INET":"AF_INET6");
for(i=0; host->h_addr_list[i]; i++)
printf("IP addr %d: %s \n",i+1,inet_ntoa(*(struct in_addr*)host->h_addr_list[i]));
return 0;
}
voie error_handling(char*message){
fputs(message,stderr);
fputc('\n',stderr);
exit(1);
}
Windows ベースの実装
Windows プラットフォームにも同様の機能を持つ同名の関数があります。まず gethostbyname 関数を紹介します。
#include<winsock2.h>
struct hostent* gethostbyname(const char *name);
//成功返回hostent结构体变量地址值,失败时返回NULL指针
関数名、パラメータ、戻り値の型はLinuxのものと同じです。次の関数を紹介します
#include<winsock2.h>
struct hostent* gethostbyaddr(const char* addr,int len,int family);
//成功时返回hostent结构体变量地址,失败时返回NULL指针
上記の機能は Linux の機能とも完全に一致しています。