getaddrinfo(一番使いそうな例)

インターネットでは、ある特定の名前に対して複数のIPアドレスが関連付けられている場合があります。 また、IPv4とIPv6の両方のアドレスがある場合には両方とも結果が返ってきます。 そのような場合、片っ端から接続を試みて実際に接続できた通信を使うという方式が一般的です。 ここでは、IPv4とIPv6両方で名前解決を行なって、さらにどんどんconnectしていって、最初にconnect出来たソケットを使うという例を説明します。

サンプルコード


#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

int
main()
{
 char *hostname = "localhost";
 char *service = "http";
 struct addrinfo hints, *res0, *res;
 int err;
 int sock;

 memset(&hints, 0, sizeof(hints));
 hints.ai_socktype = SOCK_STREAM;
 hints.ai_family = PF_UNSPEC;

 if ((err = getaddrinfo(hostname, service, &hints, &res0)) != 0) {
   printf("error %d\n", err);
   return 1;
 }

 for (res=res0; res!=NULL; res=res->ai_next) {
   sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
   if (sock < 0) {
     continue;
   }
 
   if (connect(sock, res->ai_addr, res->ai_addrlen) != 0) {
     close(sock);
     continue;
   }

   break;
 }

 if (res == NULL) {
   /* 有効な接続が出来なかった */
   printf("failed\n");

   return 1;
 }

 freeaddrinfo(res0);

 /* ここ以降にsockを使った通信を行うプログラムを書いてください */

 return 0;
}

最後に

何となく、Linuxでのgetaddrinfoの使い方を書いてみました。 試していませんが、LinuxだけでなくFreeBSDやNetBSDでもそのまま動くと思います。 もしかしたら、MacOSXでも動くかもしれません。(試してみた人がいたら教えていただけるとうれしいです。) また、「わかりにくい」「間違っている」その他ございましたら、ご指摘ください。

IPv6基礎検定

YouTubeチャンネルやってます!