ネットワーククライアントのHello World
第20回は、ネットワーククライアントのHello Worldです。これは、特定のホストの特定のポート番号にTCPで接続し、そこから受信した文字列を表示するプログラムです。具体的には、第12回で作成したネットワークサーバのプログラムに接続し、サーバから送られてくるHello Worldの文字列を表示するようなクライアント側のプログラムを作成します。
第12回では、サーバ側の動作をテストするため、クライアント側にはtelnetコマンドまたはnc(netcat)コマンドを使いましたが、今回はそのクライアント側のプログラムを、各種言語で作成してみるという趣向です。
C言語の場合
まずはC言語からです(リスト1)。ここでは、エラー処理はあえて省略しています。クライアント側のプログラムでは、socket()でソケットを作成したあと、connect()でサーバに接続します。サーバのIPアドレスとポート番号は、connect()の引数であるsockaddr_in構造体にあらかじめ値を代入しておくことによって指定します。ここでは、ループバックアドレス(127.0.0.1)の、ポート番号12345に接続することになります。
接続が確立すれば、あとは通常のファイル記述子からデータを読むのと同じように、read()でデータを読んで、write()で標準出力に出力すればOKです。なお、ここでは1回のread()で読んだデータを出力したら、プログラムを終了するようにしています。
ネットワーク接続テスト
ネットワーク接続テストを行うには、xtermなどの端末エミュレータを2つ開き、その一方でサーバ側プログラムを起動してから、他方でクライアント側プログラムを起動するようにします。
サーバ側のプログラムは、第12回で作成した各種言語用プログラムの中のひとつを使えばOKです。当然のことながら、サーバ側とクライアント側が同じ言語で書かれている必要はありません。
実行例1のように、まずサーバ側(ここではPerl版)を実行し、そのあと実行例2のようにクライアント側(ここではC言語版)を実行します。すると、クライアント側から、サーバ側であるlocalhostのTCPの12345番ポートに接続が行われ、サーバからHello Worldのメッセージが送られてきて、クライアント側に表示されます。
Perlの場合
ネットワーククライアントのプログラムを、Perlで記述するとリスト2のようになります。プログラムはC言語とよく似ており、socket()、connect()といった関数や、PF_INET、INADDR_LOOPBACKなどのラベルもC言語と同じであることがわかります。
Javaアプリケーションの場合
Javaアプリケーションで記述すると、リスト3のようになります。Javaアプリケーションでは、Socketクラスのインスタンスを作成すれば、ソケット作成とサーバへの接続が完了します。サーバからデータを受信するには、まずgetInputStream()で入力ストリームを取得して、その入力ストリームをread()します。
Pythonの場合
Pythonでは、リスト4のようにPerlに類似したコーディングになります。ただし、データの受信にはrecv()を使います。
Rubyの場合
Rubyでは、TCPSocket.open()を使うことにより、ソケット作成からサーバへの接続までが一気に行えます(リスト5)。接続完了後は、read()でデータを受信し、write()でデータを出力しています。
Tclの場合
Tclでは、リスト6のようにsocketコマンドを使ってサーバに接続します。socketはチャンネルIDを返すため、それを[ ]で取り込んでclに代入します。あとはclからreadし、そのデータをputsで出力すればOKです。putsには、余分な改行が付かないように-nonewlineオプションを付けておきます。
Bashの場合
最後に、少し変わった例として、Bashを使う方法です。Bashでは、「/dev/tcp/ホスト名/ポート番号」という特別なファイル名をリダイレクトに使用することにより、そのホストのそのポート番号に対してTCP接続を行うことができます。この/dev/tcpというのは、Bashのみで有効な仮想のファイルであり、実際に/dev/tcpというデバイスファイルが存在するわけではありません。
これを利用してネットワーククライアントを作成したのが、リスト7です。ここでは、/dev/tcp/localhost/12345をcatの標準入力にリダイレクトし、その結果をいったん変数bufに取り込んでからechoで出力しています。