はちゅにっき

こっちのブログはまったり更新

PerlでSocket通信

追記: 意外と需要があるみたいなので、しっかり動くコードにしました (2014/01/24)

IO::Socket なるモジュールを使うと、簡単にSocketプログラミングができました。


実際にSocketで作ったプログラムはもっと別モノですが
とりあえず、簡単な Echo サーバのようなモノを。
(実際に動かしていないので、エラーでるかもです)
まずはサーバ側

#
# Server side script
#
use strict;
use warnings;
use utf8;
use Carp ( );
use Encode ( );
use IO::Socket;

# コンストラクタ
my $server_socket = IO::Socket::INET->new(
    LocalPort => 2525,  # Port 番号
    Proto     => 'tcp', # Protocol
    Listen    => 1,     # Listen する数
    ReuseAddr => 1,     # なんだろ?ふつーは1だとか (あとでしらべる)
);

Carp::croak "Could not create socket: $!" unless $server_socket;

my $encoder = Encode::find_encoding('utf8');

while(1){
    # クライアントからの接続受付
    my $client_socket = $server_socket->accept;

    while(my $msg = <$client_socket>){
        # Perl 内部文字列にデコード
        $msg = $encoder->decode($msg);

        # 行末の改行を削除
        $msg =~ s/\x0D?\x0A?$//;

        # QUIT 受信で終了
        if ($msg =~ m/^QUIT$/i) {
            print 'Connection closed.';
            last;
        }

        # 受信した文字列を外部文字にエンコードし表示 & クライアントへ送信
        print 'Client>> ', $encoder->encode($msg), "\n";
        print $client_socket 'Server>> ', $encoder->encode($msg), "\n";
    }

    # Socket 閉じる
    $client_socket->close;
}

$server_socket->close;

続いてクライアント側
って、こっちは作らなくても

telnet localhost 2525

で、アクセスすればいいワケですが。

#
# Client side script
#
use strict;
use warnings;
use utf8;
use Carp ( );
use Encode ( );
use IO::Socket;

# コンストラクタ
my $socket = IO::Socket::INET->new(
    PeerAddr => 'localhost',  # 接続先
    PeerPort => 2525,         # Port 番号
    Proto    => 'tcp',        # Protocol
    TimeOut  => 5             # タイムアウト時間
);

Carp::croak "Could not create socket: $!" unless $socket;

my $encoder = Encode::find_encoding('utf8');
while(1){
    # STDIN からメッセージ受信
    print '> ';
    my $msg = <STDIN>;

    # Perl 内部文字列にデコード
    $msg = $encoder->decode($msg);

    # 行末の改行を削除
    $msg =~ s/\x0D?\x0A?$//;

    # 外部文字にエンコードしてサーバに送信
    print $socket $encoder->encode($msg), "\n";

    # Socket からメッセージを受信
    $msg = <$socket>;

    # Perl 内部文字列にデコード
    $msg = $encoder->decode($msg);

    # QUIT 受信で終了
    if ($msg =~ m/^QUIT$/i) {
        $socket->close;
        print "Connection closed by foreign host.\n";
        last;
    }

    # 外部文字にエンコードし表示
    print $encoder->encode($msg);
}

だいたいこんな感じで通信できるみたいですね。
Selectしたい場合には IO::Select を使えばいいみたいです。
お勉強になりました。
ちょっとSocketを使ったプログラムを他にも書いてみようカナ。
でも、コミットメント問題についても考えないと。。。