ネットワーク通信ではないのですが、それによく似た local domainの通信機構があります。そしてそのLOCALな通信には 2種類あり、DATAGRAM 型の通信と、STREAM型の通信があります。 前者は connection-less であり、後者は connection-oriented です。
まずは一番簡単な通信である LOCAL domain の DATAGRAM 型の通信を解説します。 この通信方法は syslogd や pccardd などで使われています。
通信を行うのは同じマシンで動いている2つのプロセスです。 一方をサーバーとし、他方をクライアントとします。 両者は通信を繋げるための目印のようなものを共有しなくてはなりません。 LOCALの通信の場合はそれは UNIX domain ソケットと呼ばれる 特殊なファイルです。別にファイルを通してデータが流れるわけではありません。 単に接続の目印です。
まずサーバー側のプログラムから見てみましょう。名前は localudps.cc です。
LOCAL DGRAM server : localudps.cc のソース、
integnet.h のソース
// LOCAL で DGRAM なソケットによる通信プログラムの雛型 (サーバー側) #include #include #include #include #include #include #include "integnet.h" // 接続の目印となるファイル #define SOCKNAME "/tmp/localudp" int main( void ) { // LOCAL で DGRAM なソケットの作成 int s = socket( AF_LOCAL, SOCK_DGRAM, 0 ); // 古い目印の削除(もし残っていると厄介) unlink( SOCKNAME ); // 接続の目印の指定 sockaddr_un addr = SOCKADDR_UN_INIT( AF_LOCAL, SOCKNAME ); // 目印の公開 bind( s, (sockaddr*)&addr, sizeof(addr) ); // データの受信 char msg[64]; int len = recvfrom( s, msg, sizeof(msg), 0, NULL, NULL ); msg[len] = '\0'; // データの表示 printf("Server received : %s\n", msg ); // ソケットの廃止 close(s); // 目印の削除(義務ではないが礼儀) unlink( SOCKNAME ); return 0; }
このプログラムを順に説明します。まず、冒頭の1文;
はLOCAL DGRAM通信用のソケットを作成します。 この段階ではまだソケットはどこにも接続されていません。次に、int s = socket( AF_LOCAL, SOCK_DGRAM, 0 );
SOCKADDR_UN_INITはsockaddr_un型変数を初期化するために私が作成したマクロです。 これは integnet.h で定義されています。 これで接続を行うための目印となる変数が作成されます。 AF_LOCALが接続が LOCALであることを指定しています。 SOCKNAMEは先に#defineで定義した UNIX domain ソケットのファイル名です。 /tmpの下に短い名前のファイルが良いでしょう。sockaddr_un addr = SOCKADDR_UN_INIT( AF_LOCAL, SOCKNAME );
このファイルが既に存在していると次のbindの作業が行えなくなるので ここでファイルを削除しています。 もし、サーバーとクライアントのプログラムの実行 ユーザーが異なる場合には、umask(0000);をここで実行しておいてください。
bind関数でソケットに先の目印を付けて接続準備完了となります。
ここでaddr変数をキャスト変換しています。bindなどのネットワーク通信用の 関数は、あらゆる種類の通信をサポートできるように汎用の型である sockaddr型で設計されています。なので UNIX LOCAL な通信に特化した型である sockaddr_un型のアドレスをこれらの関数に渡す際には sockaddr* のポインタに 変換しなくてならないのです。またその型のサイズも汎用のものと特化したものでは 異なるので、それも引数として関数に渡さなくてはなりません。 ちょっと面倒です。bind( s, (sockaddr*)&addr, sizeof(addr) );
このソケットにはクライアントから短い文字列が送信されて来ると 仮定しましょう。その文字列を受け取るには recvfrom関数を 以下のように使います。
文字列をNULLで終端しておいたほうが良いでしょう。len = recvfrom( s, msg, sizeof(msg), 0, NULL, NULL ); msg[len] = '\0';
もし、まだ何回かデータを受信したいなら、この recvfrom関数を 以下のようにループで実行するだけです。 DGRAM型の通信の場合、これで複数のクライアントからデータを 受け取ることができます。
通信を終えてソケットを使い終えたらソケットをcloseして破棄します。for(;;){ len = recvfrom( s, msg, sizeof(msg), 0, NULL, NULL ); msg[len] = '\0'; }
close(s);
次にクライアント側のプログラムを見てみましょう。名前は localudpc.cc です。
LOCAL DGRAM client : localudpc.cc のソース
// LOCAL で DGRAM なソケットによる通信プログラムの雛型 (クライアント側) #include #include #include #include #include #include #include "integnet.h" // 接続の目印となるファイル #define SOCKNAME "/tmp/localudp" int main( void ) { // LOCAL で DGRAM なソケットの作成 int s = socket( AF_LOCAL, SOCK_DGRAM, 0 ); // 送信するデータ char msg[64] = "This is client."; // 通信開始のための目印の指定 sockaddr_un addr = SOCKADDR_UN_INIT( AF_LOCAL, SOCKNAME ); // データの送信 sendto( s, msg, sizeof(msg), 0, (sockadrr*)&addr, sizeof(addr) ); // ソケットの廃止 close(s); return 0; }
sockaddr型変数やソケットの準備はサーバーと同じです。 データの送信には sendto 関数を使います。ここでは短い文章を送信しています。 送信先の情報が書かれた addr変数のアドレスをキャスト変換して sendto関数に 渡しています。
複数のデータを同じサーバーに送るには sendto関数を 複数実行するだけです。複数のサーバーに同じデータを送るには sockaddr_un型変数を適宜設定しなおして sendto関数を実行するだけです。sendto( s, msg, sizeof(msg), 0, (sockarr*)&addr, sizeof(addr) );
LOCAL DGRAM 型の通信は非常に簡単であることがわかるでしょう。