Fork me on GitHub
14/7/2006

От Perl-скрипта к Twisted-приложению: Вступление

Недавно у нас с товарищем такая ситуация возникла: ему понадобилось по определенному (текстовому) протоколу получать/отсылать данные.

Он не долго думая, написал на Perl quck&dirty скрипт, взяв за пример "форкающегося" Perl-демона. Что-то примерно такое:

#!/usr/bin/perl -w
# serverfork.pl - a server that forks a child
# process to handle client connections
use strict;
use IO::Socket;
use Sys::Hostname;
use POSIX qw(:sys_wait_h);
use DBI;

# perl's black magic for reaping childs by parent

sub REAP {
    1 until (-1 == waitpid(-1, WNOHANG));
    $SIG{CHLD} = \&REAP;
}
$SIG{CHLD} = \&REAP;

my $sock = new IO::Socket::INET(
                  LocalHost => '0.0.0.0',
                      LocalPort => 3000,
                          Proto     => 'tcp',
                          Listen    => SOMAXCONN,
                          Reuse     => 1);
$sock or die "no socket :$!";
STDOUT->autoflush(1);
my($new_sock, $buf, $kid);
my $fio;
while ($new_sock = $sock->accept()) {
    # execute a fork, if this is
    # the parent, its work is done,
    # go straight to continue
    next if $kid = fork;
    die "fork: $!" unless defined $kid;
    # child now...
    # close the server - not needed
    close $sock;

    while (defined($buf = <$new_sock>)) {
    chop $buf;
        # parsing packet....
        $num = parse_packet($buf);
        print "trying to send answer...\n";
        print defined($new_sock) ?  "socket good\n" : "socket bad\n"; 
        if ($fio = get_client($sess{num})){
            print "client:\t".$fio;
            my $packet = make_packet($fio);
            print $new_sock $packet."\r\n";
       }
    }
    sleep(10);
    exit;
} continue {
    # parent closes the client since
    # it is not needed
   close $new_sock;
}

sub parse_packet{
    # dummy parser
    my $buf = shift;
    return substr($buf,10,5)
}

sub make_packet{
    # dummy maker
    my $fio = shift;
    return "dummypacketmaker0123456789".$fio
}

sub get_client{
    my $num = shift;
    # ... some actions with DB for fetching client's name by agreem's number
    # f.e. it would be 'Nikanorov Ivan Nikifirovich'
    $name = 'Nikanorov Ivan Nikifirovich';

    my @a = split /\s+/, $name if $i==1;

    return  ( $i==1 ? substr($a[0],0,16).(defined($a[1])? '_'.substr($a[1],0,1).( defined($a[2]) ? '_'.substr($a[2],0,1)
                                             : '' )
                        : ''
                  )
        : 0
    );

}

И вот с этим Perl-демоном у него возникла проблема: после некоторого времени работы один из "детей" съедал все ресурсы процессора. И товарищ попросил глянуть свежим взглядом, может я увижу. Я посмотрел, и предложил: давай я тебе этот демон напишу на Python, но при условии, что я смогу опубликовать "процесс". Он согласился.

Первоначально я задумывал переписать Perl-код 1-к-1, но потом вспомнил, что не так давно смотрел twisted и он мне тогда приглянулся. Напомню, что это фреймворк для создания асинхронных приложений, преимущественно сетевых.

В общем, взялся переписать на twisted python. Что было в процессе и что в итоге получилось опишу чуть позже.

Комментарии

Все статьи