echoサーバーを書こう
2010-12-10
        こんにちは、@lopnorこと檀上です。と、これまで誰も名乗らずにここまできてしまいましたJPerl Advent Calendar 2010 - perl6 trackですが、ここでこれまでの執筆者をご紹介します。
- @risouさん
- [/articles/advent-calendar/2010/perl6/7:title=インタラクティブな実行環境を使おう]
 
 - @uasiさん
- [/articles/advent-calendar/2010/perl6/8:title=モジュールを公開してみよう]
 
 - @VienosNotesさん
- [/articles/advent-calendar/2010/perl6/9:title=『Perl6入門』入門]
 
 - @lopnor
- 残りの記事
 
 
です。まだまだ原稿が足りないので、Perl 6について語っちゃうよ!という方はぜひお声がけください。よろしくお願いします!
echoサーバーを書こう
さて、今日はネットワークプログラミングに挑戦です。先日twitterのタイムラインを読んでくるスクリプトがありましたが、やっぱり今時ネットワーク経由でデータをやり取りしてナンボ、というところがあります。前回はクライアントでしたが、今回はサーバーをつくってみようと思います。というとまずはechoサーバーを書かないといけないですね。
echoサーバーの動作イメージはこんな感じです。
$ perl6 echo_server.pl 5000 & [1] 4980 $ telnet 127.0.0.1 5000 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. hoge hoge fuga fuga ^] telnet> quit Connection closed.
echo_server.plはこんな感じ。
#!/usr/bin/env perl6
use v6;
# constants
sub PF_INET {2}
sub SOCK_STREAM {1}
sub TCP {6}
sub MAIN ($port = '5000', :$host = '0.0.0.0') {
    my $server = IO::Socket::INET.socket( PF_INET, SOCK_STREAM, TCP );
    $server.bind($host, $port);
    $server.listen;
    while my $conn = $server.accept {
        while my $str = $conn.recv {
            $conn.send($str);
        }
        $conn.close;
    }
    $server.close;
}
# vim: ft=perl6 :
と、何の変哲もないコードでした。これで僕の環境ではちゃんと動きます。で、これ実はほとんどrakudo/t/spec/S32-io/IO-Socket-INET.plからパクったものなんですが、これがspectest.dataからコメントアウトされており、いくつかの環境で正しく動作しない模様です。はやくなおるといいですね。
ベンチマーク
さて、このサーバーとperl5で書いたサーバーを比較してみました。
#!perl
use strict;
use warnings;
use IO::Socket;
my $server = IO::Socket::INET->new(
    LocalPort => 5000,
    Listen => SOMAXCONN,
    Reuse => 1,
);
while (my $conn = $server->accept) {
    while ($conn->sysread(my $str, 1024)) {
        $conn->syswrite($str);
    }
    $conn->close;
}
$server->close;
# from http://d.hatena.ne.jp/naoya/20070311/1173629378
こんなの。これを、別のマシンから
$ time (for i in `seq 1 1000`; do echo $i | nc 10.0.87.6 5000 > /dev/null;done)
としてみました。
# perl6 $ time (for i in `seq 1 1000`; do echo $i | nc 10.0.87.6 5000 > /dev/null;done) (; for i in `seq 1 1000`; do; echo $i | nc 10.0.87.6 5000 > /dev/null; done; ) 0.68s user 2.78s system 19% cpu 17.548 total # perl5 $ time (for i in `seq 1 1000`; do echo $i | nc 10.0.87.6 5000 > /dev/null;done) (; for i in `seq 1 1000`; do; echo $i | nc 10.0.87.6 5000 > /dev/null; done; ) 0.68s user 2.80s system 20% cpu 16.667 total
大差ないですね。つないでやり取りして切る、だけであればそれほど差はないようです。このあと、httpサーバーを書くなどした場合、文字列処理で差が出てくるのだと思います。