サーバを作るまず、ソケットでIPv4あるいはIPv6クライアントからの接続を受け付けるプログラムを作ってみる。onlyのときの典型的なコードは、次のようになる。IPv4のアドレスしか格納できない。これではIPv6で通信はできない。ソケットアドレスの生成〜listen()IPv6ということで、AF_INET6とsockaddr_in6を使ってみるか。適切なソケットアドレス情報などを生成させ、それでソケットを生成し、bind()などを行う。ソケットアドレス構造体が得られれば、それ以降はIPv4と大差ない。キモはgetaddrinfo()にある。プロトタイプ宣言は次のとおり。nodenameはホスト名またはIPアドレスの文字列、servnameはポート番号またはサービス名、hintsはヒントを引数として与える。ヒントの制約にしたがってgetaddrinfo()はresにソケットアドレスのリストを生成する。IPアドレスでソケットを生成できる。サーバでは、通常はNULLでいいだろう。hintsとして渡すaddrinfo構造体は、次のメンバを持つ。<netdb.h>ヘッダで定義される。ai_next;};いずれも0を設定すると、制約を課さずに、任意の組み合わせを得られる。ai_protocolは、socket()に与える値とする。ここではai_familyにはAF_INET6を設定する。後のセクションで、ai_familyにAF_UNSPECを設定して、IPv4/IPv6二つのソケットアドレスを得る方法も解説する。IPv6クライアントからしか接続できなくなってしまう。ソケットを2つ作らないといけない。Vista以降は問題ない。(Windows)ai_flagsにいろいろな値を設定して、getaddrinfo()の挙動を制御できる。AI_PASSIVEソケットアドレスをbind()する場合に指定。AI_CANONNAMEホストの正式名を要求する。AI_NUMERICHOSTnodenameは数値形式のネットワークアドレスに限る。ホスト名の名前解決は行わない。AI_NUMERICSERVservnameはポート番号の文字列に限る。IPv6アドレスを返す。ai_familyがAF_INET6でない場合、AI_V4MAPPEDは無視される。IPv6アドレスの両方を返す。AI_V4MAPPEDフラグなしに指定した場合、AI_ALLフラグは無視される。AI_ADDRCONFIGローカルシステムがIPv4アドレスを持つ場合に限りIPv4アドレスを取得し、ローカルシステムがIPv6アドレスを持つ場合に限りIPv6アドレスを取得する。実際のコードは、次のようになる。C++コンパイラでもコンパイルできる。ヘッダファイルの取り込み、デバッグ用表示関数は省略。AF_INET6は、IPv4/IPv6両方を受け付ける。bind()する場合は指定する。-1;ソケットアドレスを得たら、あとはIPv4のときと大差ない。socket()でソケットを生成し、bind()でIPアドレスと結びつけ、listen()でlistenキューを生成する。freeaddrinfo()でソケットアドレスのリストを解放するのを忘れずに。}接続を受け付け、通信するクライアントからの接続を受ける場合、一番簡単なのは、accept()でブロックしてしまう。accept()は接続を受け付けたら新しいソケットを生成してそれを返す。ソケットアドレス構造体は、IPv4、IPv6で大きさが違う。sockaddr_storageは、システムでサポートされているソケットアドレス構造体のどれよりも大きいことが確かなので、ソケットアドレス構造体を格納するときはこれを使う。sockaddr_unだけが定められている。sockaddr_ipxなどもある。len);そうしたら、forkして、親プロセスはクライアントからの接続を待ちつつ、子プロセスで通信を行う。クライアントを作る(2006.6.29の日記を加筆。)クライアントは、サーバに接続する部分をIPv4/IPv6両対応にする。IPv6の違いを意識する必要はない。IPv6でもIPv4と同様にホスト名とポート番号の組み合わせでサーバに接続する。サーバがIPv4にしか対応していない場合、IPv6にしか対応していない場合があるので、IPv4のみで接続するときに比べてコードがいくぶん長くなる。関数は、サーバを制作するときと同様、ヒントにしたがって接続先のソケットアドレスの選択肢を返す。クライアントではホスト名も与える。getaddrinfo()は、ヒントのai_familyがAF_UNSPECで、指定したホスト名がIPv4アドレス、IPv6アドレスの両方を持つ場合に限り、二つのソケットアドレスを返す。ないときは一つだけ返す。ホスト名の名前解決も行う。serviceはポート番号でなければならない。'pop'などでもよい。}接続アドレスに対して順に接続できるかどうか試していく。IPv4、IPv6アドレスのどちらを先に返すかは分からないので、このコードではIPv4/IPv6の両方を受け付けるサーバに対してどちらで接続するかは決められない。簡単に、1バイト送信し1バイト受信して表示するだけ。IPv4を区別するサーバ(2006.6.29の日記を加筆。)今度は、IPv6のときのみ違うサービスが提供できるよう、IPv6専用ソケット、IPv4専用ソケットを作ってみよう。ヒントのai_familyをAF_UNSPECにすると、複数のソケットアドレスを得られる。これらを順にbind()し、listen()していく。IPv4/IPv6専用ソケットを作る。acceptするためにbind()する場合は指定する。-1;IPv6ソケットに対してIPV6_V6ONLYソケットオプションを設定すると、このソケットはIPv6でのみ通信できる。IPv6で提案され、POSIXにもある。IPv6ソケットはIPv6からの接続だけ受け付ける。listenすればいい。ブロックするわけにはいかない。ブロックしてしまうと指定したソケット以外のソケットで受け付けられない。あとは先ほどのサーバと同じ。