Perl Telnet 会话处理程序

发布于 2024-10-16 01:32:16 字数 5041 浏览 1 评论 0原文

我有一个应用程序,可以按需连接到网络中的各种设备,执行多个命令,解析输出并通过 AJAX/JSON/Perl 向用户报告。在 Perl 中,我使用 NET::Telnet / ::Cisco,以及偶尔通过生成子进程并将其传递给 NET:: 的 SSH 连接。远程登录。

我希望通过创建一种 telnet 会话持有者来增强应用程序,该持有者将在连接打开一段时间后或直到超时之前保持连接。其想法是减少重新连接到这些设备的次数,并允许其他请求使用之前创建的 telnet 会话(前提是该会话未使用且仍处于活动状态)。

我开始使用 IO::Socket::UNIX 编写一个 perl 文件,并且能够存储没有问题的连接,基本上另一个文件将使用创建的套接字来访问或创建新连接。我遇到的问题是:如果两个请求同时到达该套接字,则第一个请求将导致第二个请求必须等待第一个请求完成处理。

我开始尝试使用线程,但如果这样做,我无法将NET::Telnet对象传递回原始/父线程。

有谁对如何实现这一目标有任何想法?是否有一个应用程序可以充当我可以与之交互的会话持有者?

更新

我根据一位评论者的建议使用了 POE,虽然这部分满足了我的要求,但它不允许“服务器”同时为多个连接提供服务。

设想: 两个用户在前端单击“发送”时距离很近。用户 A 的查询首先到达服务器,但他们正在尝试连接到需要很长时间才能响应的设备。因此,在用户 B 的请求开始之前,用户 B 必须等到用户 A 的连接建立。本质上

,我需要能够使用连接池服务同时请求,而不会给其他任何人造成延迟,只是因为第一个到达那里的人正在尝试连接到那个 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;
    }
}

I have an application that makes connections to various equipment in our network on demand, performs several commands, parses the output and reports back to the user via AJAX/JSON/Perl. In Perl, I am using NET::Telnet / ::Cisco, along with the occasional SSH connection via spawning a child process and passing that to NET::Telnet.

I am looking to enhance the application by creating a sort of telnet session holder that will maintain connections after they are opened for a set period of time, or until they time out. The idea is to cut down on the reconnecting to these devices, and allowing other requests to use a telnet session that was created before (provided it's not in use and is still active).

I started writing a perl file using IO::Socket::UNIX, and am able to store the connections w/o issue, and basically another file will use the socket created to access or create new connections. The problem I am having is this: If two requests hit that socket at the same time, which ever one came in first will cause the second one to have to wait for the first to be done processing.

I started experimenting with using threads, but if I do that, I can't pass the NET::Telnet object back to the original/parent thread.

Does anyone have any ideas on how to accomplish this? Is there maybe an application that will act as a session holder that I can interface with?

UPDATE

I used POE per the suggestion from one commenter, and while this does partially what I'm looking for, it does not allow the 'server' to service multiple connections simultaneously.

Scenario:
Two users click 'send' on the front end rather close together. User A's query reaches the server first, but they are trying to connect to a device that takes a long time to respond. Thusly, User B will have to wait until User A's connection is established before User B's request is even started. Essentially

, I need to be able to service simultaneous requests using a connection pool without creating delay for anyone else just because the guy that got there first is trying to connect to that slooooow device..

Below is my code which, if this is how I would do it, will be run in the background. The prints are for my debugging.

#!/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;
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

2024-10-23 01:32:17

我已转而使用 POE 服务器架构,并生成子/子进程来处理各个连接。这可能不是做我想做的事情的最漂亮/最好/最有效的方式,但它完成了工作并且有一个不同的狭窄目的。

感谢大家的帮助。

I have moved to using POE server architecture, along with spawning sub/child-processes to handle individual connections. It's probably not the prettiest/best/most efficient way to do what I want, but it gets the job done and has a vary narrow purpose.

Thanks everyone to all their help.

于我来说 2024-10-23 01:32:16

听起来您需要使用 ResourcePool 来完成此任务。只需在池中创建所需数量的对象,然后使用 get 和 free 来使用它们并将它们放回池中。

It sounds like you need to use ResourcePool to accomplish this. Just create the number of objects you need in the pool then use get and free to use them and drop them back in the pool.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文