図 2-1 と次の 2 つの例は、インターネットファミリのストリーム接続の開始と受け入れを示しています。
例 2-1 はサーバー側のプログラムです。このプログラムは、ソケットを作成してそのソケットに名前をバインドし、続いてポート番号を表示します。このプログラムは listen(3SOCKET) を呼び出して、ソケットが接続要求を受け入れる用意ができていることをマークし、要求の待ち行列を初期化します。プログラムの残り部分は無限ループです。ループの各パスは、新しいソケットを作成することによって新しい接続を受け入れ、待ち行列からその接続を削除します。サーバーは、ソケットからのメッセージを読み取って表示し、メッセージを閉じます。in6addr_any の使用については、「アドレスのバインド」で説明しています。
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #define TRUE 1 /* * このプログラムは、ソケットを作成したあと無限ループを開始します。 * ループごとに接続を受け入れ、その接続からのデータを出力します。 * 接続が遮断するか、あるいはクライアントが接続を閉じる時点で * プログラムは新しい接続を受け入れます。 */ main() { int sock, length; struct sockaddr_in6 server; int msgsock; char buf[1024]; int rval; /* ソケットを作成する。*/ sock = socket(AF_INET6, SOCK_STREAM, 0); if (sock == -1) { perror("opening stream socket"); exit(1); } /* ワイルドカードを使用してソケットをバインドする。*/ bzero (&server, sizeof(server)); bzero (&sin6, sizeof (sin6)); server.sin6_family = AF_INET6; server.sin6_addr.s6_addr = in6addr_any; server.sin6_port = 0; if (bind(sock, (struct sockaddr *) &server, sizeof server) == -1) { perror("binding stream socket"); exit(1); } /* 割り当てられたポート番号を調べ、それを出力する。*/ length = sizeof server; if (getsockname(sock,(struct sockaddr *) &server,&length) == -1) { perror("getting socket name"); exit(1); } printf("Socket port #%d¥n", ntohs(server.sin6_port)); /* 接続の受け入れを開始する。*/ listen(sock, 5); do { msgsock = accept(sock,(struct sockaddr *) 0,(int *) 0); if (msgsock == -1 perror("accept"); else do { memset(buf, 0, sizeof buf); if ((rval = read(msgsock,buf, 1024)) == -1) perror("reading stream message"); if (rval == 0) printf("Ending connection¥n"); else /* データが出力可能であると想定する */ printf("-->%s¥n", buf); } while (rval > 0); close(msgsock); } while(TRUE); /* * このプログラムには無限ループが含まれるため、ソケット "sock" は * 明示的に閉じられることはありません。しかし、プロセスが中断されるか * 正常に終了する場合は自動的に閉じます。 */ exit(0); }
接続を開始するため、例 2-2 のクライアント側プログラムは、ストリームソケットを作成し、接続用のソケットのアドレスを指定して connect(3SOCKET) を呼び出します。宛先ソケットが存在し、要求が受け入れられる場合は、接続が完了し、プログラムはデータを送信できます。データは、メッセージ境界なしで順番に配信されます。接続は、一方のソケットが閉じられた時点で遮断されます。このプログラム内のデータ表現ルーチン (ntohl(3SOCKET)、ntohs(3SOCKET)、 htons(3SOCKET)、htonl(3XNET) など) の詳細については、byteorder(3SOCKET) のマニュアルページを参照してください。
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #define DATA "Half a league, half a league . . ." /* * このプログラムはソケットを作成し、コマンド行で指定 * されるソケットを使用して接続を開始します。この接続で * データがいくらか送信されたあとソケットが閉じられ、 * 接続が終了します。 * コマンド行の書式: streamwrite hostname portnumber * 使用法: pgm host port */ main(argc, argv) int argc; char *argv[]; { int sock, errnum h_addr_index; struct sockaddr_in6 server; struct hostent *hp; char buf[1024]; /* ソケットを作成する。*/ sock = socket( AF_INET6, SOCK_STREAM, 0); if (sock == -1) { perror("opening stream socket"); exit(1); } /* コマンド行で指定される名前を使用してソケットを接続する。*/ bzero (&sin6, sizeof (sin6)); server.sin6_family = AF_INET6; hp = getipnodebyname(AF_INET6, argv[1], AI_DEFAULT, &errnum); /* * getinodebyname が、指定されたホストのネットワーク * アドレスを含む構造体を返す。 */ if (hp == (struct hostent *) 0) { fprintf(stderr, "%s: unknown host¥n", argv[1]); exit(2); } h_addr_index = 0; while (hp->h_addr_list[h_addr_index] != NULL) { bcopy(hp->h_addr_list[h_addr_index], &server.sin6_addr, hp->h_length); server.sin6_port = htons(atoi(argv[2])); if (connect(sock, (struct sockaddr *) &server, sizeof (server)) == -1) { if (hp->h_addr_list[++h_addr_index] != NULL) { /* 次のアドレスを試みる */ continue; } perror("connecting stream socket"); freehostent(hp); exit(1); } break; } freehostent(hp); if (write( sock, DATA, sizeof DATA) == -1) perror("writing on stream socket"); close(sock); freehostent (hp); exit(0); }