いよいよInternet domain でのネットワーク通信です。 異なるマシンで動く2つのプロセス で DGRAM型の通信を行います。この通信プロトコルは UDP/IP と呼ばれています。 この通信方法は youbind などで使われています。
INETの場合は接続の目印にはポートと呼ばれる番号を使います。
まずサーバー側のプログラムから見てみましょう。名前は inetudps.cc です。
INET DGRAM server : inetudps.cc のソース、
integnet.h のソース
// INET で DGRAM な UDPソケットによる通信プログラムの雛型 (サーバー側) #include #include #include #include #include #include #include "integnet.h" // 接続のポート #define PORT 12345 int main( void ) { // INET で DGRAM なソケットの作成 int s = socket( AF_INET, SOCK_DGRAM, 0 ); // 接続の目印の指定 sockaddr_in addr = SOCKADDR_IN_INIT( AF_INET, htons(PORT), InAddr(htonl(INADDR_ANY)) ); // 目印の公開 if( bind( s, (sockaddr*)&addr, sizeof(addr) ) < 0 ){ perror("bind"); exit(1); } // データの受信 char msg[64]; int len = recvfrom( s, msg, sizeof(msg), 0, NULL, NULL ); msg[len] = '\0'; // データの表示 printf("Server received : %s\n", msg ); // ソケットの廃止 close(s); return 0; }
ソケットを AF_INET で作成します。
目印の指定を sockaddr_in 型構造体で行っています。
その初期化には私が作成したマクロ SOCKADDR_IN_INITを用います。sockaddr_in addr = SOCKADDR_IN_INIT( AF_INET, htons(PORT), InAddr(htonl(INADDR_ANY)) );
PORTは #defineで定義したポートの値(この例では 12345)です。 これを sockaddr 型変数に指定する際は必ず htons関数で network byte order に 変換して下さい。INADDR_ANY はそのマシンのどのネットワーク装置からの アクセスも受け付けることを意味します。接続するクライアントのIPアドレスでは ありません。この INADDR_ANY は "0.0.0.0" のIPを表す 4byte の整数として 定義されているのですが、これを sockaddr型変数に指定する際には、まず htonl関数でnetwork byte order に変換して、それを in_addr 型に変換すべく InAddr関数を使ってください。
bindで指定のポートにソケットが接続されます。クライアントとの 接続の準備が完了します。LOCALの時にはbindの失敗をチェックしていませんでしたが、 INETの場合にはチェックすべきです。 LOCALのbindがファイルを作るだけなので、消せばすぐに消えるものなのですが、 INETの ポートというものは閉じてもなかなか消えるものではなりません。 なので、サーバーを再起動するときにここでエラーになることが多いです。
recvfrom関数の最後の2つの引数からクライアントの情報を得ることができますが この例ではそれを利用していません。
次にクライアント側のプログラムを見てみましょう。名前は inetudpc.cc です。
INET DGRAM client : inetudpc.cc のソース
// INET で DGRAM な UDPソケットによる通信プログラムの雛型 (クライアント側) #include #include #include #include #include #include #include #include "integnet.h" // 接続のポート #define PORT 12345 #define HOSI "127.0.0.1" int main( void ) { // INET で DGRAM なソケットの作成 int s = socket( AF_INET, SOCK_DGRAM, 0 ); // 送信するデータ char msg[64] = "This is client."; // 接続の目印の指定 sockaddr_in addr = SOCKADDR_IN_INIT( AF_INET, htons(PORT), InAddr(HOST) ); if( h_errno ){ herror("gethostbyname"); exit(1); } // データの送信 sendto( s, msg, sizeof(msg), 0, (sockaddr*)&addr, sizeof(addr) ); // ソケットの廃止 close(s); return 0; }
sockaddr_in型変数の指定で第4引数に接続相手のホスト名を指定するのですが ここではIPアドレスの文字列 "127.0.0.1" で指定しています。 つまり同じマシンにサーバープロセスがあると仮定しています。もし別のマシンの サーバープロセスに接続するならここにそのホスト名を記述してください。 もしホストのIPアドレスが見つからない場合には広域変数 h_errno が 0以外になっていますのでエラーとして終了してください。
sendto関数で宛先にデータを送信します。
Internetドメインでの connect関数や sendto関数は クライアント側の空きポートからパケットを送信して、 サーバー側の目的のポートに届けようとします。 Internetドメインでの通信での接続とはサーバーとクライアントの両方の IPアドレスとPORTのペアの接続なのです。例えば以下のような接続です。
Server | IP 123.45.67.8 | PORT 80 |
Client | IP 234.56.78.9 | PORT 1025 |
connect関数や sendto関数は発信に使うポートを 1025番から 順順に探していきます。もし特定の番号のポートで発信したいなら その前に bind を使います。これについては後で説明します。