Perl Telnet Обработчик Сессий - PullRequest
       5

Perl Telnet Обработчик Сессий

0 голосов
/ 04 февраля 2011

У меня есть приложение, которое устанавливает соединения с различным оборудованием в нашей сети по требованию, выполняет несколько команд, анализирует выходные данные и отправляет отчеты пользователю через AJAX / JSON / Perl. В Perl я использую NET :: Telnet / :: Cisco , а также время от времени SSH-соединение через порождение дочернего процесса и передачу его в NET :: Telnet .

Я хочу улучшить приложение, создав своего рода держатель сеанса telnet, который будет поддерживать соединения после того, как они открыты в течение заданного периода времени или до истечения времени ожидания. Идея состоит в том, чтобы сократить повторное подключение к этим устройствам и разрешить другим запросам использовать сеанс telnet, который был создан ранее (при условии, что он не используется и все еще активен).

Я начал писать файл perl, используя IO :: Socket :: UNIX , и могу хранить соединения без проблемы, и в основном другой файл будет использовать сокет, созданный для доступа или создания нового соединения. Проблема, с которой я сталкиваюсь, заключается в следующем: если два запроса попадают в один и тот же сокет одновременно, то какой бы один из них ни пришел первым, второй будет вынужден ждать обработки первого.

Я начал экспериментировать с использованием потоков , но если я это сделаю, я не смогу передать объект NET :: Telnet обратно в исходный / родительский поток.

У кого-нибудь есть идеи, как этого добиться? Может быть, есть приложение, которое будет действовать как держатель сеанса, с которым я могу взаимодействовать?

UPDATE

Я использовал POE в соответствии с предложением одного комментатора, и хотя это частично выполняет то, что я ищу, оно не позволяет «серверу» одновременно обслуживать несколько соединений.

Сценарий: Два пользователя нажимают «отправить» на переднем конце довольно близко друг к другу. Сначала запрос пользователя A достигает сервера, но он пытается подключиться к устройству, на ответ которого уходит много времени. Таким образом, пользователю B придется подождать, пока соединение пользователя A не будет установлено, прежде чем запрос пользователя B будет даже запущен. По существу

, мне нужно иметь возможность обслуживать одновременные запросы, используя пул соединений, не создавая задержки для кого-либо еще только потому, что парень, который первым пришел туда, пытается подключиться к этому устройству slooooow ..

Ниже приведен мой код, который, если я так сделаю, будет выполняться в фоновом режиме. Отпечатки для моей отладки.

#!/usr/bin/perl -w

use strict;
use JSON;
use Net::Telnet;
use IO::Socket::UNIX qw( SOCK_STREAM SOMAXCONN );

my $socketPath = '/tmp/telnetproxy';
unlink($socketPath);

my $listener = IO::Socket::UNIX->new(
    Type   => SOCK_STREAM,
    Local  => $socketPath,
    Listen => SOMAXCONN) 
    or die ("Cannot create server socket: $!\n");

my $clientNum = 0;

our $json = JSON->new->allow_nonref;
our $conns = {};

print "Server Initiated...\n";

while (1) {

    print " - Inside while loop...\n";

    my $socket = $listener->accept();

    connectToDevice(++ $clientNum, $socket);

}

sub connectToDevice {
    my $connectionNum = shift;
    my $socket = shift;

    print " - Inside 'connectToDevice'\n";

    print " - Connection #$connectionNum started...\n";

    my $input;
    my $connId = 0;
    my (@argsRaw, $args, @argHold);
    my $numOfConnections = keys %$conns;

    my $deviceProperties = {
        ipAddress => undef,
        username  => undef,
        password  => undef,
        method    => 'telnet'
    };

    print " - waiting for input...\n";

    # Receive input for arguments.
    chomp( $input = <$socket> );

    print " - input received...\n";

    ## Turn string into a HASHREF
    $args = from_json($input);

    foreach (keys %$args) {
        print "\t$connectionNum: $_ => $args->{$_}\n";
        if (/^host$/i) { #---- Host IP given ($self->{_hostIp{
            if (verifyIp($args->{$_})) {
                $deviceProperties->{ipAddress} = $args->{$_};
            } else {

            }
        }
         elsif (/^method$/i) { # Ckt type... very important for how we ts
            $deviceProperties->{method} = $args->{$_};
        }
         elsif (/^(username|user|u)$/i) { # username to log in with
            $deviceProperties->{username} = $args->{$_};
        }
         elsif (/^(password|pass|p)$/i) { # password
            $deviceProperties->{password} = $args->{$_};
        }
    }

    print " - Num of connections: $numOfConnections\n";

    if ($numOfConnections > 0) {
        ## Look through existing connections
        ##  1) If we have an available connection, use it
        ##  2) If not, create a new connection.
        print " - Checking existing connections...\n";
        foreach my $connKey ( keys %$conns ) {
            if ($conns->{$connKey}->{host} eq $deviceProperties->{ipAddress} && $conns->{$connKey}->{locked} == 0 && testConnection($connKey)) {
                $connId = $connKey;
                print "\tconnection #$connKey... VALID, using it\n";
                last;
            } else {
                print "\tconnection #$connKey... not valid\n";
            }
        }
    } else {
        print " - No existing connections, creating a new one ...\n";
    }

    if ($connId == 0) {

        $connId = $connectionNum;

        $conns->{$connectionNum} = {
            host   => $deviceProperties->{ipAddress},
            locked => 1
        };

        $conns->{$connectionNum}->{conn} = connectToHost($deviceProperties, "blab_$connectionNum");
        print " - Created a new connection, a suitable existing connection was not found.\n";
    }

    print " - Waiting for command.. ";

    chomp( my $line = <$socket> );

    print "DONE\n";

    my @out = $conns->{$connId}->{conn}->cmd($line);

    print " - Sent '$line' to device\n";

    my $numOfLines = @out;

    print " - $numOfLines lines retrieved\n";

    $conns->{$connId}->{locked} = 0;

    print " - This run done....\n\n";

    return;
}

sub testConnection {
    my $connectionNum = shift;

    print " -- Testing connection $connectionNum:  ";

    my @out = $conns->{$connectionNum}->{conn}->cmd(String => '!', Timeout => 2);

    print "[";
    print @out;
    print "]";

    if (@out > 0) {
        print " ---- Good\n";
        return 1;
    } else {
        delete $conns->{$connectionNum};
        print " ---- No good\n";
        return 0;
    }
}

Ответы [ 2 ]

0 голосов
/ 11 февраля 2011

Я перешел на использование архитектуры сервера POE, а также порождал дочерние / дочерние процессы для обработки отдельных соединений.Вероятно, это не самый красивый / лучший / самый эффективный способ делать то, что я хочу, но он выполняет свою работу и имеет узкую цель.

Спасибо всем за помощь.

0 голосов
/ 04 февраля 2011

Похоже, вам нужно использовать ResourcePool для этого. Просто создайте необходимое количество объектов в пуле, затем используйте get и free, чтобы использовать их, и отбросьте их обратно в пул.

...