この付録では,クライアント/サーバ・プログラムの例として,注釈付きのファイルを記載します。 クライアントはサーバに要求を送り,サーバからの応答を出力します。 サーバはクライアントからの要求をリッスンし,要求を出力して,応答をクライアントに送ります。
このプログラムは実際に使用されているアプリケーションではありませんが,各種のソケット呼び出しのシーケンスと使用方法を示すように構成されています。
情報は,次のように編成されています。
これらのプログラムと,これらのクライアント・プログラムのプロトコル非依存バージョンが,/usr/examples/ipv6/network_programming
ディレクトリにあります。
この付録では,これらのプログラムの出力例も記載しています。
C.1 AF_INET ソケットを使用するプログラム
この節には,AF_INET ソケットを使用するクライアントおよびサーバ・プログラムを記載します。
C.1.1 AF_INET ソケットを使用するクライアント・プログラム
例 C-1
は,ユーザのシステムで作成,コンパイル,実行が可能なクライアント・プログラムの例を示しています。
このプログラムは,コマンド行で指定したシステムに要求を送信し,そこから応答を受信します。
例 C-1: クライアント・スタブ・ルーチン
/* * ***************************************************************** * * * * * Copyright (c) Compaq Computer Corporation, 2000 * * * * * * The software contained on this media is proprietary to * * * and embodies the confidential technology of Compaq * * * Computer Corporation. Possession, use, duplication or * * * dissemination of the software and media is authorized only * * * pursuant to a valid written license from Compaq Computer * * * Corporation. * * * * * * RESTRICTED RIGHTS LEGEND Use, duplication, or disclosure * * * by the U.S. Government is subject to restrictions as set * * * forth in Subparagraph (c)(1)(ii) of DFARS 252.227-7013, * * * or in FAR 52.227-19, as applicable. * * * * * ***************************************************************** */ #include <sys/types.h> #include <sys/socket.h> #include <sys/errno.h> #include <netinet/in.h> #include <netdb.h> #include <string.h> #include <stdio.h> #include <signal.h> #include <stdlib.h> #include <arpa/inet.h> #define SERVER_PORT 7639 #define CLIENT_PORT 7739 #define MAXBUFSIZE 4096 int main ( int argc, char **argv ) { int s; char databuf[MAXBUFSIZE]; int dcount; struct sockaddr_in serveraddr; [1] struct sockaddr_in clientaddr; int serveraddrlen; const char *ap; const char *request = "this is the client's request"; struct hostent *hp; char *server; if (argc < 2) { printf("Usage: client <server>\n"); exit(1); } server = argv[1]; bzero((char *) &serveraddr, sizeof(struct sockaddr_in)); [2] serveraddr.sin_family = AF_INET; if ((hp = gethostbyname(server)) == NULL) { [3] printf("unknown host: %s\n", server); exit(2); } serveraddr.sin_port = htons(SERVER_PORT); while (hp->h_addr_list[0] != NULL) { if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { [4] perror("socket"); exit(3); } memcpy(&serveraddr.sin_addr.s_addr, hp->h_addr_list[0], hp->h_length); if (connect(s, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) { [5] perror("connect"); close(s); hp->h_addr_list++; continue; } break; } if (send(s, request, strlen(request), 0) < 0) { [6] perror("send"); exit(5); } dcount = recv(s, databuf, sizeof(databuf), 0); [7] if (dcount < 0) { perror("recv"); exit(6); } databuf[dcount] = '\0'; hp = gethostbyaddr((char *)&serveraddr.sin_addr.s_addr, [8] sizeof(serveraddr.sin_addr.s_addr), AF_INET); ap = inet_ntoa(serveraddr.sin_addr); [9] printf("Response received from"); if (hp != NULL) printf(" %s", hp->h_name); if (ap != NULL) printf(" (%s)", ap); printf(": %s\n", databuf); close(s); }
sockaddr_in
構造体を宣言する。
この型の構造体の使用は,ソケット (AF_INET) の通信ドメインにより指示され,これによって通信に IPv4 プロトコルが使用されます。
[例に戻る]
サーバ・アドレスをクリアし,サーバ変数を設定する。 IPv4 通信のソケット・アドレスは,32 ビット・インターネット・アドレスと 16 ビットのポート番号からなります。 このアドレスは,サーバのインターネット・アドレスとサーバがリッスンするポート番号になります。 [例に戻る]
サーバの IPv4 アドレスを取得する。
gethostbyname
の呼び出しでは,IPv4 アドレスのみが返されます。
[例に戻る]
socket
呼び出しで AF_INET ソケットを作成する。
TCP またはコネクション指向型通信用にソケット・タイプ SOCK_STREAM を指定しています。
[例に戻る]
serveraddr
という名前の
sockaddr_in
構造体内のアドレスを使用して,サーバに接続する。
[例に戻る]
サーバに要求を送信する。 [例に戻る]
サーバから応答を受信する。 [例に戻る]
serveraddr
という名前の
sockaddr_in
構造体内のアドレスを使用して,サーバ名を取り出す。
gethostbyaddr
呼び出しは,入力として IPv4 アドレスを期待しています。
[例に戻る]
サーバの 32 ビット IPv4 アドレスを,ドット表記のインターネット・アドレス・テキスト文字列に変換する。
inet_ntoa
呼び出しは,入力として IPv4 アドレスを期待しています。
[例に戻る]
例 C-2
は,ユーザのシステムで作成,コンパイル,実行が可能なサーバ・プログラムの例を示しています。
このプログラムは他のシステムで稼働しているクライアント・プログラムから要求を受信し,応答を送信します。
例 C-2: サーバ・スタブ・ルーチン
/* * ***************************************************************** * * * * * Copyright (c) Compaq Computer Corporation, 2000 * * * * * * The software contained on this media is proprietary to * * * and embodies the confidential technology of Compaq * * * Computer Corporation. Possession, use, duplication or * * * dissemination of the software and media is authorized only * * * pursuant to a valid written license from Compaq Computer * * * Corporation. * * * * * * RESTRICTED RIGHTS LEGEND Use, duplication, or disclosure * * * by the U.S. Government is subject to restrictions as set * * * forth in Subparagraph (c)(1)(ii) of DFARS 252.227-7013, * * * or in FAR 52.227-19, as applicable. * * * * * ***************************************************************** */ #include <sys/types.h> #include <sys/socket.h> #include <sys/errno.h> #include <netinet/in.h> #include <netdb.h> #include <string.h> #include <stdio.h> #include <signal.h> #include <stdlib.h> #include <arpa/inet.h> #define SERVER_PORT 7639 #define CLIENT_PORT 7739 #define MAXBUFSIZE 4096 int main ( int argc, char **argv ) { int s; char databuf[MAXBUFSIZE]; int dcount; struct sockaddr_in serveraddr; [1] struct sockaddr_in clientaddr; int clientaddrlen; struct hostent *hp; const char *ap; const char *response = "this is the server's response"; u_short port; if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { [2] perror("socket"); exit(1); } bzero((char *) &serveraddr, sizeof(struct sockaddr_in)); [3] serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); [4] serveraddr.sin_port = htons(SERVER_PORT); if (bind(s, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) { [5] perror("bind"); exit(2); } if (listen(s, SOMAXCONN) < 0) { [6] perror("Listen"); close(s); exit(3); while (1) { int new_s; clientaddrlen = sizeof(clientaddr); new_s = accept(s, (struct sockaddr *)&clientaddr, &clientaddrlen); [7] dcount = recv(new_s, databuf, sizeof(databuf), 0); [8] if (dcount <= 0) { perror("recv"); close(new_s); continue; } databuf[dcount] = '\0'; hp = gethostbyaddr((char *)&clientaddr.sin_addr.s_addr, [9] sizeof(clientaddr.sin_addr.s_addr), AF_INET); ap = inet_ntoa(clientaddr.sin_addr); [10] port = ntohs(clientaddr.sin_port); printf("Request received from"); if (hp != NULL) printf(" %s", hp->h_name); if (ap != NULL) printf(" (%s)", ap); printf(" port %d \"%s\"\n", port, databuf); if (send(new_s, response, strlen(response), 0) < 0) { [11] perror("send"); close(new_s); continue; } close(new_s); } close(s); }
sockaddr_in
構造体を宣言する。
この型の構造体の使用は,ソケット (AF_INET) の通信ドメインにより指示され,これによって通信に IPv4 プロトコルが使用されます。
[例に戻る]
AF_INET ソケットを作成する。 TCP またはコネクション指向型通信用にソケット・タイプ SOCK_STREAM を指定しています。 [例に戻る]
サーバ・アドレスをクリアし,サーバ変数を設定する。 IPv4 通信のソケット・アドレスは,32 ビット・インターネット・アドレスと 16 ビットのポート番号からなります。 このアドレスは,サーバのインターネット・アドレスとサーバがリッスンするポート番号になります。 [例に戻る]
サーバ・アドレスに,IPv4 ワイルドカード・アドレス INADDR_ANY を設定する。 このアドレスは,システム上に実装されている任意のネットワーク・インタフェースを指定します。 [例に戻る]
サーバのアドレスを,AF_INET ソケットにバインドする。 [例に戻る]
ソケット上でコネクションをリッスンする。
サーバは,以前の
accept
呼び出しの処理が終わるまで,最大 SOMAXCONN 個の保留コネクションをキューイングします。
ソケット・サブシステムのカーネル属性についての詳細は,
sys_attrs_socket
(5)
このソケット上のコネクションを受け付ける。
accept
呼び出しはクライアントのアドレスを,clientaddr
という名前の
sockaddr_in
構造体に格納します。
[例に戻る]
データをクライアントから受信する。 [例に戻る]
clientaddr
という名前の
sockaddr_in
構造体内のアドレスを使用して,クライアント名を取り出す。
gethostbyaddr
呼び出しは,入力として IPv4 アドレスを期待しています。
[例に戻る]
サーバの 32 ビットの IPv4 アドレスを,ドット表記のインターネット・アドレス・テキスト文字列に変換する。
inet_ntoa
呼び出しは,入力として IPv4 アドレスを期待しています。
[例に戻る]
クライアントに応答を送信する。 [例に戻る]
この節には,AF_INET6 ソケットを使用するクライアントおよびサーバ・プログラムを記載します。
C.2.1 AF_INET6 ソケットを使用するクライアント・プログラム
例 C-3
は,ユーザのシステムで作成,コンパイル,実行が可能なクライアント・プログラムの例を示しています。
このプログラムは,コマンド行で指定したシステムに要求を送信し,そこから応答を受信します。
すべてのアドレスは,IPv6 アドレス・フォーマットです。
例 C-3: クライアント・スタブ・ルーチン
/* * ***************************************************************** * * * * * Copyright (c) Compaq Computer Corporation, 2000 * * * * * * The software contained on this media is proprietary to * * * and embodies the confidential technology of Compaq * * * Computer Corporation. Possession, use, duplication or * * * dissemination of the software and media is authorized only * * * pursuant to a valid written license from Compaq Computer * * * Corporation. * * * * * * RESTRICTED RIGHTS LEGEND Use, duplication, or disclosure * * * by the U.S. Government is subject to restrictions as set * * * forth in Subparagraph (c)(1)(ii) of DFARS 252.227-7013, * * * or in FAR 52.227-19, as applicable. * * * * * ***************************************************************** */ #include <sys/types.h> #include <sys/socket.h> #include <sys/errno.h> #include <netinet/in.h> #include <netdb.h> #include <string.h> #include <stdio.h> #include <signal.h> #include <stdlib.h> #include <arpa/inet.h> #define SERVER_PORT 7639 #define CLIENT_PORT 7739 #define MAXBUFSIZE 4096 int main ( int argc, char **argv ) { int s; char databuf[MAXBUFSIZE]; int dcount; struct addrinfo *server_info; [1] struct addrinfo *cur_info; struct addrinfo hints; struct sockaddr_in6 serveraddr; [2] char addrbuf[INET6_ADDRSTRLEN]; char node[MAXDNAME]; char service[MAXDNAME]; int ni; int err; int serveraddrlen; const char *request = "this is the client's request"; char *server; if (argc < 2) { printf("Usage: client <server>\n"); exit(1); } server = argv[1]; bzero((char *) &hints, sizeof(hints)); [3] hints.ai_family = AF_INET6; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = AI_ADDRCONFIG | AI_V4MAPPED; sprintf(service, "%d", SERVER_PORT); err = getaddrinfo(server, service, &hints, &server_info); [4] if (err != 0) { printf("%s\n", gai_strerror(err)); if (err == EAI_SYSTEM) perror("getaddrinfo"); exit(2); } cur_info = server_info; while (cur_info != NULL) { if ((s = socket(cur_info->ai_family, cur_info->ai_socktype, 0)) < 0) { [5] perror("socket"); freeaddrinfo(server_info); exit(3); } if (connect(s, cur_info->ai_addr, cur_info->ai_addrlen) <0 { [6] close(s); cur_info = cur_info->ai_next; continue; } break; } freeaddrinfo(server_info); [7] if (send(s, request, strlen(request), 0) < 0) { [8] perror("send"); exit(5); } dcount = recv(s, databuf, sizeof(databuf), 0); [9] if (dcount < 0) { perror("recv"); exit(6); } databuf[dcount] = '\0'; serveraddrlen = sizeof(serveraddr); if (getpeername(s, (struct sockaddr*) &serveraddr, &serveraddrlen) < 0) { [10] perror("getpeername"); exit(7); } printf("Response received from"); ni = getnameinfo((struct sockaddr*)&serveraddr, serveraddrlen, [11] node, sizeof(node), NULL, 0, NI_NAMEREQD); if (ni == 0) printf(" %s", node); ni = getnameinfo((struct sockaddr*)&serveraddr, serveraddrlen, [12] addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST); if (ni == 0) printf(" (%s)", addrbuf); printf(": %s\n", databuf); close(s); }
addrinfo
構造体と
hints
構造体を宣言する。
[例に戻る]
sockaddr_in6
構造体を宣言する。
この型の構造体の使用は,ソケット (AF_INET6) の通信ドメインにより指示され,これによって通信に IPv6 プロトコルが使用されます。
プロトコルに依存しないプログラムを作成したい場合は,sockaddr_storage
構造体を宣言します。
[例に戻る]
アドレス文字列バッファ,ノード名文字列バッファ,サービス名文字列バッファ,エラー番号変数,サービス・アドレス長変数を宣言する。 [例に戻る]
hints
構造体をクリアし,hints 変数を設定する。
hints
構造体には,getaddrinfo
の処理を指定する値が格納されています。
この場合,AF_INET6 により IPv6 アドレスが返されます。
IPv6 アドレスが構成されている場合,AI_ADDRCONFIG 値および AI_V4MAPPED 値により AAA レコードが返されます。
また,IPv6 アドレスがない場合,IPv4 アドレスが構成されていれば,A レコードが返されます。
hints
構造体の値についての詳細は,
getaddrinfo
(3)
サーバ・アドレスを取得する。
getaddrinfo
を呼び出すと,1 つ以上の
addrinfo
型の構造体で,IPv6 フォーマットのアドレスが返されます。
[例に戻る]
AF_INET6 ソケットを作成する。
ソケット・タイプは,addrinfo
構造体で指定します。
[例に戻る]
cur_info
という名前の
addrinfo
構造体内のアドレスを使用して,サーバに接続する。
[例に戻る]
すべての
addrinfo
構造体を解放する。
[例に戻る]
サーバに要求を送信する。 [例に戻る]
サーバから応答を受信する。 [例に戻る]
コネクションの他端にあるピア・ソケットのアドレスを取得し,そのアドレスを
serverinfo
という名前の
sockaddr_in6
構造体に格納する。
[例に戻る]
serveraddr
という名前の
sockaddr_in6
構造体内のアドレスを使用して
getnameinfo
を呼び出し,サーバ名を取得する。
NI_NAMEREQD フラグは,このルーチンが,指定されたアドレスのホスト名を返すように指示しています。
[例に戻る]
serveraddr
という名前の
sockaddr_in6
構造体内のアドレスを使用して
getnameinfo
を呼び出し,サーバの数値アドレスを取得する。
NI_NUMERICHOST フラグは,このルーチンが,指定されたアドレスのアドレス値を返すように指示しています。
[例に戻る]
例 C-4
は,ユーザのシステムで作成,コンパイル,実行が可能なサーバ・プログラムの例を示しています。
このプログラムは他のシステムで稼働しているクライアント・プログラムから要求を受信し,応答を送信します。
例 C-4: サーバ・スタブ・ルーチン
/* * ***************************************************************** * * * * * Copyright (c) Compaq Computer Corporation, 2000 * * * * * * The software contained on this media is proprietary to * * * and embodies the confidential technology of Compaq * * * Computer Corporation. Possession, use, duplication or * * * dissemination of the software and media is authorized only * * * pursuant to a valid written license from Compaq Computer * * * Corporation. * * * * * * RESTRICTED RIGHTS LEGEND Use, duplication, or disclosure * * * by the U.S. Government is subject to restrictions as set * * * forth in Subparagraph (c)(1)(ii) of DFARS 252.227-7013, * * * or in FAR 52.227-19, as applicable. * * * * * ***************************************************************** */ #include <sys/types.h> #include <sys/socket.h> #include <sys/errno.h> #include <netinet/in.h> #include <netdb.h> #include <string.h> #include <stdio.h> #include <signal.h> #include <stdlib.h> #include <arpa/inet.h> #define SERVER_PORT 7639 #define CLIENT_PORT 7739 #define MAXBUFSIZE 4096 int main ( int argc, char **argv ) { int s; char databuf[MAXBUFSIZE]; int dcount; struct sockaddr_in6 serveraddr; [1] struct sockaddr_storage clientaddr; [2] char addrbuf[INET6_ADDRSTRLEN]; char node[MAXDNAME]; char port[MAXDNAME]; int err; int ni; int clientaddrlen; const char *response = "this is the server's response"; if ((s = socket(AF_INET6, SOCK_STREAM, 0)) < 0) { [3] perror("socket"); exit(1); } bzero((char *) &serveraddr, sizeof(struct sockaddr_in6)); [4] serveraddr.sin6_family = AF_INET6; serveraddr.sin6_addr = in6addr_any; serveraddr.sin6_port = htons(SERVER_PORT); if (bind(s, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) { [5] perror("bind"); exit(2); } if (listen(s, SOMAXCONN) < 0) { [6] perror("listen"); close(s); exit(3); } while (1) { int new_s; clientaddrlen = sizeof(clientaddr); bzero((char *)&clientaddr, clientaddrlen); [7] new_s = accept(s, (struct sockaddr*)&clientaddr, &clientaddrlen); [8] if (new_s < 0) { perror("accept"); continue; } dcount = recv(new_s, databuf, sizeof(databuf), 0); [9] if (dcount < 0) { perror("recv"); close(new_s); continue; } databuf[dcount] = '\0'; printf("Request received from"); ni = getnameinfo((struct sockaddr *)&clientaddr, [10] clientaddrlen, node, sizeof(node), NULL, 0, NI_NAMEREQD); if (ni == 0) printf(" %s", node); ni = getnameinfo((struct sockaddr *)&clientaddr, [11] clientaddrlen, addrbuf, sizeof(addrbuf), port, sizeof(port), NI_NUMERICHOST|NI_NUMERICSERV); if (ni == 0) printf(" (%s) port %d", addrbuf, port); printf(" \"%s\"\n", port, databuf); if (send(new_s, response, strlen(response), 0) < 0) { [12] perror("send"); close(new_s); continue; } close(new_s); } close(s); }
serveraddr
という名前の
sockaddr_in6
構造体を宣言する。
この型の構造体の使用は,ソケット (AF_INET6) の通信ドメインにより指示され,これによって通信に IPv6 プロトコルが使用されます。
[例に戻る]
clientaddr
という名前の
sockaddr_storage
構造体を宣言する。
この型の構造体を使用すると,プログラムをプロトコル非依存にすることができます。
[例に戻る]
AF_INET6 ソケットを作成する。 TCP またはコネクション指向型通信用にソケット・タイプ SOCK_STREAM を指定しています。 [例に戻る]
サーバ・アドレスをクリアし,サーバ変数を設定する。 [例に戻る]
サーバのアドレスを,AF_INET ソケットにバインドする。 [例に戻る]
ソケット上でコネクションをリッスンする。
サーバは,以前の
accept
呼び出しの処理が終わるまで,最大 SOMAXCONN 個の保留コネクションをキューイングします。
ソケット・サブシステムのカーネル属性についての詳細は,
sys_attrs_socket
(5)
クライアント・アドレスをクリアする。 [例に戻る]
このソケット上のコネクションを受け付ける。
accept
呼び出しは,クライアントのアドレスを,clientaddr
という名前の
sockaddr_storage
構造体に格納します。
[例に戻る]
データをクライアントから受信する。 [例に戻る]
clientaddr
という名前の
sockaddr_storage
構造体内のアドレスを使用して
getnameinfo
を呼び出し,クライアント名を取得する。
NI_NAMEREQD フラグは,このルーチンが,指定されたアドレスのホスト名を返すように指示しています。
[例に戻る]
clientaddr
という名前の
sockaddr_storage
構造体内のアドレスを使用して
getnameinfo
を呼び出し,クライアントの数値アドレスとポート番号を取得する。
NI_NUMERICHOST フラグと NI_NUMERICSERV フラグは,このルーチンが,指定されたアドレスとポート番号に対応する数値を返すように指示しています。
[例に戻る]
クライアントに応答を送信する。 [例に戻る]
この節では,サーバ・プログラムとクライアント・プログラムの出力例を示します。
サーバ・プログラムは AF_INET6 ソケット上の要求はすべて,sockaddr_in6
を用いて受け付け,受信します。
IPv4 で受信した要求では,sockaddr_in6
には IPv4 にマップされた IPv6 アドレスが格納されています。
次の例では,ノード
hostb6
でクライアント・プログラムが実行中であり,ノード
hosta6
に要求を送信しています。
このプログラムは AF_INET6 ソケットを使用します。
hosta6
ノードの IPv6 アドレスは,DNS (Domain Name System) で 3ffe:1200::a00:2bff:fe97:7be0 になっています。
user2@hostb6> ./client hosta6 Response received from hosta6.ipv6.corp.example (3ffe:1200::a00:2bff:fe97:7be0): this is the server's response
サーバ・ノードでは,次の例でサーバ・プログラムの起動とクライアント・ノード
hostb6
からの要求の受信を示します。
user1@hosta6> ./server Request received from hostb6.ipv6.corp.example (3ffe:1200::a00:2bff:fe2d:02b2 port 7739 "this is the client's request"
次の例では,ノード
hostb
でクライアント・プログラムが実行中であり,ノード
hosta
に要求を送信しています。
プログラムは AF_INET6 ソケットを使用します。
hosta
ノードの IPv4 アドレスは,DNS で 10.10.10.13 になっています。
user2@hostb> ./client hosta Response received from hosta.corp.example (::ffff:10.10.10.13): this is the server's response
サーバ・ノードでは,次の例でサーバ・プログラムの起動とクライアント・ノード
hostb
からの要求の受信を示します。
user1@hosta6> ./server Request received from hostb.corp.example (::ffff:10.10.10.251) port 7739 "this is the client's request"
次の例では,ノード
hostc
でクライアント・プログラムが実行中であり,ノード
hosta
に要求を送信しています。
このプログラムは,IPv4 のみのシステムで AF_INET ソケットを用いて作成され,実行されたものです。
user3@hostc> ./client hosta Response received from hosta.corp.example (10.10.10.13): this is the server's response
サーバ・ノードでは,次の例でサーバ・プログラムの起動とクライアント・ノード
hostc
からの要求の受信を示します。
user1@hosta6>./server Request received from hostc.corp.example (::ffff:10.10.10.63) port 7739 "this is the client's request"