モジュールを使ってみよう (1)

TOP >> ネットワークプログラミングの基礎知識 >> モジュールを使ってみよう (1)

(追記) (追記ここまで)
(追記) (追記ここまで) (追記) (追記ここまで)

モジュールとは

perl にはモジュールという拡張機能があります。 モジュールには perl に標準で付いてくるモジュール (Socket モジュールもその一つです) と、 自分で後からインストールしなければならないモジュールがあります。

IO::Socket

ここではもう一つのモジュール、IO::Socket モジュールを紹介しましょう。 IO::Socket モジュールも標準モジュールなので、 わざわざインストールする必要はありません。

以下のスクリプトは、文字列を送って文字列を返すだけの echo クライアントです。

% ./echo-client-io-socket.pl hostname 1234
で、hostname のポート 1234 番に接続します。 もちろん hostname で echo サーバがポート 1234 を listen している 必要があります。
% ./echo-client-io-socket.pl
と引数を省略すると、localhost のポート7番に接続します。

接続すると、line 1、line 2...という文字列を echo サーバに送信し、 echo サーバからのレスポンスを受信します。

localhost:7 に接続します。
送信メッセージ: line 1
受信メッセージ: line 1
送信メッセージ: line 2
受信メッセージ: line 2
送信メッセージ: line 3
受信メッセージ: line 3
送信メッセージ: line 4
受信メッセージ: line 4
送信メッセージ: line 5
受信メッセージ: line 5
送ったものをそのまま返すだけの echo サーバですから、 もちろん送信メッセージと受信メッセージの内容は同じです。

echo-client-io-socket.pl

 1: #!/usr/local/bin/perl
 2: 
 3: # $Id: echo-client-io-socket.pl,v 1.1 2001年04月21日 18:56:39 68user Exp $
 4: 
 5: use IO::Socket; # IO::Socket モジュールを使う。
 6: 
 7: # ホスト名とポート番号を設定
 8: $host = shift || 'localhost';
 9: $port = shift || getservbyname('echo','tcp') || 7;
 10: 
 11: print "$host:$port に接続します。\n";
 12: 
 13: $socket = IO::Socket::INET->new(PeerAddr => $host,
 14: PeerPort => $port,
 15: Proto => 'tcp',
 16: );
 17: if ( ! $socket ){
 18: die "接続できませんでした。 $!\n";
 19: }
 20: 
 21: for (1..5){
 22: # 文字列を送信
 23: print "送信メッセージ: line $_\n";
 24: print $socket "line $_\n";
 25: $socket->flush();
 26: 
 27: # 文字列を受信
 28: $buf = <$socket>;
 29: print "受信メッセージ: $buf";
 30: }
 31: 
 32: $socket->close();
まず、
 5: use IO::Socket; # IO::Socket モジュールを使う。
で、IO::Socket モジュールを使うことを宣言します。 これを書かないとエラーになります。

これまでのクライアントで使った getservbyname、inet_aton、sockaddr_in、socket、connect は 一切出てきません。それらの部分は

 13: $socket = IO::Socket::INET->new(PeerAddr => $host,
 14: PeerPort => $port,
 15: Proto => 'tcp',
 16: );
によって全て内部で行われています。楽ですね。 引数には
  • PeerAddr ... 接続したいホスト名
  • PeerPort ... 接続したいポート番号
  • Proto ... プロトコル名。ここでは 'tcp' を指定します
を渡します。
なお、Reuse=>1=> は , (カンマ) と同じ意味ですが、=> を使った方が、 引数の対応がわかりやすくなります。

また、$socket = IO::Socket::INET->new("$host:$port"); という省略形でも指定できます。

IO::Socket::INET->new がファイルハンドルを返すことに注意して下さい。 これを変数に代入し、これ以降はこの変数 (ファイルハンドル) に対して入出力を行います。


あとは、メッセージを送って受け取るだけです。

 21: for (1..5){
 22: # 文字列を送信
 23: print "送信メッセージ: line $_\n";
 24: print $socket "line $_\n";
 25: $socket->flush();
 26: 
 27: # 文字列を受信
 28: $buf = <$socket>;
 29: print "受信メッセージ: $buf";
 30: }
文字列を送信した後は、flush でデータを送信しています。 毎回 flush でバッファをクリアせず、IO::Socket::INET->new の 後に
select($socket); $|=1;
と、バッファリングしない設定にするのでもいいでしょう。
perl5.005_05 の perldoc IO::Socket には
As of VERSION 1.18 all IO::Socket objects have autoflush turned on by default. This was not the case with earlier releases.
つまり、IO::Socket の version 1.18 以降は、IO::Socket の 生成するソケットは、デフォルトでバッファリングしない ようになっている、とあります。ここでは念のため、 明示的にバッファリングを OFF にしています。
文字列の送信後は、echo サーバから1行受け取り、それをそのまま表示します。
 32: $socket->close();
最後にソケットを close して終了です。

オブジェクト指向

オブジェクト指向とは何かを説明し出すと、いつになっても終わらないので、 表面的な部分だけ書きます。
use FOO;
$obj = FOO->new;
$obj->func1();
$obj->func2(10,20);
$obj->end();
use FOO で、クラス FOO を使用することを宣言します。 FOO->new とすると、クラス FOO のオブジェクトを返します。 オブジェクトとは、たくさんの変数が詰まったものだと思って下さい。 $obj->func1() とすると、クラス FOO のメソッド (関数のようなもの) である func1 を $obj に対して実行します。

C のような関数型プログラミングで書くと、

$data = FOO_init;
&FOO_func1($data);
&FOO_func2($data,10,20);
&FOO_end($data);
のような感じでしょうか。

はっきり言えば、変数名が先にくるか、それとも関数名が先にくるかの違いです。 「変数名->関数名」という書き方をオブジェクト指向というのだ、と 思ってもらって結構です。実際、

 32: $socket->close();
close($socket);
とも書けます。
こんな いいかげんな説明、OOP 好きの人が読んだら怒るだろうな...。
(追記) (追記ここまで) (追記) (追記ここまで)

TOP >> ネットワークプログラミングの基礎知識 >> モジュールを使ってみよう (1)

ご意見・ご指摘は Twitter: @68user までお願いします。



AltStyle によって変換されたページ (->オリジナル) /