【问题标题】:Better way to handle perl sockets to read/write to active proccess处理 perl 套接字以读取/写入活动进程的更好方法
【发布时间】:2014-09-18 20:02:40
【问题描述】:

首先,我要感谢你们没有提供解决方案作为解决方案(尽管知道其他方法会很酷)。我正在设置 tg-master 项目(用于 cli 的电报)以供 check_mk 警报插件使用。我发现电报在标准输入/标准输出进程上运行,所以我认为“粘合”它会很酷,所以我用博客中的很多构建块编写了接下来的 2 段代码。他们已经工作了(我有时需要处理破损的管道),但我想知道是否可以分享一些专家的新想法。

正如您所见,我的代码依赖于一个 eval,它从生成的进程中读取一个 die,我知道这不是最好的方法。有什么建议么? :D

谢谢大家

服务器

use strict;

use IO::Socket::INET;
use IPC::Open2;
use POSIX;
our $pid;

use sigtrap qw/handler signal_handler normal-signals/;

sub signal_handler {
    print "what a signal $!\nlets kill $pid\n";
    kill 'SIGKILL', $pid;
    #die "Caught a signal $!";
}

# auto-flush on socket
$| = 1;
# creating a listening socket
my $socket = new IO::Socket::INET(
    LocalHost => '0.0.0.0',
    LocalPort => '7777',
    Proto     => 'tcp',
    Listen    => 5,
    Reuse     => 1
);
die "cannot create socket $!\n" unless $socket;
print "server waiting for client connection on port 7777\n";
my ( $read_proc, $write_proc );

my ( $uid, $gid ) = ( getpwnam "nagios" )[ 2, 3 ];
POSIX::setgid($gid);    # GID must be set before UID!
POSIX::setuid($uid);

$pid = open2( $read_proc, $write_proc, '/usr/bin/telegram' );

#flush first messages;
eval {
    local $SIG{ALRM} = sub { die "Timeout" };    # alarm handler
    alarm(1);
    while (<$read_proc>) { }
};
while (1) {
    my $client_socket  = $socket->accept();
    my $client_address = $client_socket->peerhost();
    my $client_port    = $client_socket->peerport();
    print "connection from $client_address:$client_port\n";

    # read until \n
    my $data = "";
    $data = $client_socket->getline();
    # write to spawned process stdin the line we got on $data
    print $write_proc $data;
    $data = "";

    eval {
        local $SIG{ALRM} = sub { die "Timeout" };    # alarm handler
        alarm(1);

        while (<$read_proc>) {
            $client_socket->send($_);
        }
    };
    # notify client that response has been sent
    shutdown( $client_socket, 1 );
}
$socket->close();

客户

echo "contact_list" | nc localhost 7777

echo "msg user#12345 NAGIOS ALERT ... etc" | nc localhost 7777

其他一些 perl 脚本 =)

【问题讨论】:

    标签: perl sockets process pipe


    【解决方案1】:

    如果您要实现一个脚本来执行从/到不同句柄的读取和写入,请考虑使用select(在文档中定义为select RBITS,WBITS,EBITS,TIMEOUT)。在这种情况下,您将完全避免使用 alarmeval 中的信号处理程序来处理超时,并且只会有一个循环,所有工作都在其中发生。

    下面是一个程序示例,它从使用open2 打开的进程和网络套接字读取,根本不使用alarm

    use strict;
    use warnings;
    use IO::Socket;
    use IPC::Open2;
    use constant MAXLENGTH => 1024;
    
    my $socket = IO::Socket::INET->new(
            Listen => SOMAXCONN,
            LocalHost => '0.0.0.0',
            LocalPort => 7777,
            Reuse => 1,
    );
    
    # accepting just one connection
    print "waiting for connection...\n";
    my $remote = $socket->accept();
    print "remote client connected\n";
    
    # simple example of the program writing something
    my $pid = open2(my $localread, my $localwrite, "sh -c 'while : ; do echo boom; sleep 1 ; done'");
    
    for ( ; ; ) {
            # cleanup vectors for select
            my $rin = '';
            my $win = '';
            my $ein = '';
    
            # will wait for a possibility to read from these two descriptors
            vec($rin, fileno($localread), 1) = 1;
            vec($rin, fileno($remote), 1) = 1;
    
            # now wait
            select($rin, $win, $ein, undef);
    
            # check which one is ready. read with sysread, not <>, as select doc warns
            if (vec($rin, fileno($localread), 1)) {
                    print "read from local process: ";
                    sysread($localread, my $data, MAXLENGTH);
                    print $data;
            }
            if (vec($rin, fileno($remote), 1)) {
                    print "read from remote client: ";
                    sysread($remote, my $data, MAXLENGTH);
                    print $data;
            }
    }
    

    在实际生产代码中,您需要仔细检查各种函数(套接字创建、open2acceptselect)返回的错误。

    【讨论】:

    • 这段代码导致了一个疯狂的进程,并且不允许客户端退出。这个想法是在处理许多连接、发送命令、接收响应和断开连接的客户端时保持本地守护进程“活动”。 ./socket-play.pl 等待连接... 远程客户端已连接 从远程客户端读取:kaboom 从远程客户端读取:从远程客户端读取:从远程客户端读取:从远程客户端读取:从远程客户端读取:从远程读取客户端:从远程客户端读取:从远程客户端读取:从远程客户端读取:从远程客户端读取:从远程客户端读取:
    猜你喜欢
    • 1970-01-01
    • 2017-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-12
    • 1970-01-01
    • 1970-01-01
    • 2020-09-28
    相关资源
    最近更新 更多