プログラミングインタフェース

ストリームソケットのコネクション

次の 2 つの例に、インターネットファミリのストリームコネクションの開始と受け入れを示します。

図 6–1 ストリームソケットを使用したコネクション型の通信

この図はクライアントとサーバー間のデータフローを示します。accept と connect そして read と write の関数ペアを使用します。

次のプログラムはサーバーの例です。このサーバーは、ソケットを作成し、そのソケットに名前をバインドし、そして、ポート番号を表示します。このプログラムは listen(3SOCKET) を呼び出して、ソケットがコネクション要求を受け入れる用意ができていることをマークし、要求の待ち行列を初期化します。プログラムの残りの部分は無限ループです。ループの各パスは、新しいソケットを作成することによって新しいコネクションを受け入れ、待ち行列からそのコネクションを削除します。サーバーは、ソケットからのメッセージを読み取って表示し、ソケットを閉じます。in6addr_any の使用については、アドレスのバインドで説明しています。


例 6–1 インターネットストリームコネクションの受け入れ (サーバー)

#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 = 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);
}

例 6–2 のクライアント側プログラムは、コネクションを開始するために、ストリームソケットを作成し、コネクション用のソケットのアドレスを指定して connect(3SOCKET) を呼び出します。宛先ソケットが存在し、要求が受け入れられる場合、 コネクションは完了します。すると、プログラムはデータを送信できます。データは、メッセージ境界なしで順番に配信されます。コネクションは、一方のソケットが閉じられた時点で遮断されます。このプログラム内のデータ表現ルーチン (ntohl(3SOCKET)、ntohs(3SOCKET)、htons(3SOCKET)、および htonl(3XNET) など) の詳細については、byteorder(3SOCKET) のマニュアルページを参照してください。


例 6–2 インターネットファミリのストリームコネクション(クライアント)

#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 part
 */ 
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 (&server, sizeof (server));
    server.sin6_family = AF_INET6;
    hp = getipnodebyname(argv[1], AF_INET6, AI_DEFAULT, &errnum);
/*
 * getipnodebyname が指定されたホストのネットワークアドレスを含む
 * 構造体を返す
 */
    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);
}