図 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);
}