ソケットは次に触れるネットワークプログラムにも使われるプロセス間通信 の技法です。同一の計算機の上でもネットワークを介しても基本的に同じ方式 で通信ができます。ソケットはそういった通信の端点(終点)を表わします。こ こでは同一の計算機の上での場合を見ます。ネットワークへの拡張は次の節で 行います。以下に説明するシステムコールの引数の意味や構造体の型が同一計 算機の場合とネットワークの場合では少し違ってきますので注意が必要です。
最初にすることはまずソケットを開設することです。socketシステムコール を使います。
#include <sys/types.h> #include <sys/socket.h> int fd; fd = socket( PF_UNIX, SOCK_STREAM, 0);
最初の引数PF_UNIXはドメインを表わし、今の場合は同一計算機上であること を表わします。PF_INETを指定するとインターネット接続になります。次の引 数SOCK_STREAMは接続形態を表わし、今の場合はストリーム型をさします。 SOCK_DGRAMを指定するとデータグラム型通信になります。最後の引数0はプロ トコル番号で、0はドメインとタイプで決まるプロトコル番号を使用すること を示します。
ソケット通信では通信する二つのプロセスの片側がクライアント、相手がサー バであることを想定しています。クライアント側では用意したソケットを特定 のサーバに接続したいと考えます。サーバ側はどこのクライアントから接続要 求があるかは知りません。このためサーバのソケットには名前を付けて、クラ イアント側はその名前を使って接続要求を出すことになります。ですから次の 手順はサーバ側のソケットに名前を付けることになります。bindシステムコー ルを使います。
struct sockaddr sa; sa.sa_family = AF_UNIX; strcpy( sa.sa_data, "sock_test" ); if( bind( fd, &sa, sizeof( sa ) ) == -1 ) { /* 戻り値が-1はエラー */ }
以後sock_testという名前がこのソケットに付けられました。このプログラム を走らせた段階でls -lをやってみてください。sock_testというファイルが出 来ていることがわかります。ファイルがソケットアドレスを表わすsの属性を 持っています。クライアント側はこの名前さえ知っていれば通信できることに なります。通信経路を確保すると言ったことをしないデータグラム型通信では ここでsendtoやrecvfromを使って通信します。通信経路を確保するストリーム 型通信ではさらに経路確立の手順が必要です。まずサーバ側でクライアントか らの経路確立要求を待ちます。その準備のためにlistenシステムコールを使い ます。
if( listen( fd, 5 ) == -1 ) { /* 戻り値が-1の時はエラー */ }
これで通信経路確立要求がクライアントから出されたらそれを受け付けること ができるようになります。実際に要求をうけつけるにはさらにacceptシステム コールを発行します。
int so; struct sockaddr sa; int salen; sa.sa_family = AF_UNIX; strcpy( sa.sa_data, "sock_test" ); salen = sizeof( sa ); if( ( so = accept( fd, &sa, &salen ) ) == -1 ) { /* 戻り値が-1の時はエラー、それ以外はファイル記述子 */ }
引数saはbindで使ったものです。acceptの戻り値はこのソケットに新たに割り 付けられたファイル記述子です。データのやり取りはこの新しいファイル記述 子soを使って行います。もとのファイル記述子fdは引き続き接続要求を受け付 けるのに使われます。
ではクライアント側に行きましょう。socketシステムコールでソケットを確 保したらそれへの接続を要求します。connectシステムコールを使います。
#include <sys/types.h> #include <sys/socket.h> struct sockaddr sa; sa.sa_family = AF_UNIX; strcpy( sa.sa_data, "sock_test" ); if( connect( fd, &sa, sizeof( sa ) ) == -1 ) { /* 戻り値が-1の時はエラー */ }
connectが成功するとソケットfdを使ってサーバと通信が可能になります。 sendシステムコールで送信しrecvシステムコールで受信します。
int len; char buf[ 256 ]; strcpy( buf, "Now sending a message from client A" ); len = send( fd, buf, strlen( buf ), 0 ); if( len == -1 ) { /* 戻り値が-1の時はエラー */ } len = recv( fd, buf, 256, 0 ); if( len == -1 ) { /* 戻り値が-1の時はエラー */ }
サーバ側も同じです。
通信が終了すると接続を破棄しなければなりません。shutdownで接続を断っ たうえでファイル記述子を閉じます。
shutdown( fd, 2 ); close( fd );
以上で手順は完了です。