2014-09-18 61 views
0

首先,我要感謝你們不提供解決方案作爲解決方案(儘管瞭解其他方法可以很酷)。我正在爲check_mk alert插件使用tg-master項目(cli的電報)。我發現電報是在一個stdin/stdout進程上運行的,所以我認爲將它「粘合」起來會很酷,所以我用很多來自博客的構建塊編寫了代碼,並編寫了接下來的兩段代碼。他們已經工作(我有時需要處理破損的管道),但我想知道是否可以從一些專家的新想法分享。更好的方式來處理perl套接字來讀/寫活動進程

正如你所看到的,我的代碼依賴於從衍生過程中讀取死亡的eval,我知道不是最好的方法。有什麼建議麼? :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腳本=)

回答

0

如果你要實現執行讀取和從/到不同的手柄寫了一個腳本,可以考慮使用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; 
     } 
} 

在實際生產代碼,你需要仔細檢查各種函數返回的錯誤(套接字創建,open2,acceptselect)。

+0

此代碼導致瘋狂的進程,並且不允許客戶端退出。 這個想法是在處理許多客戶端連接,發送命令,接收響應和斷開連接時保持本地守護進程「活着」。 ./socket-play.pl 等待連接... 遠程客戶端連接從遠程客戶端讀取 :從遠程客戶端讀取KABOOM :從遠程客戶端讀取:從遠程客戶端讀取:從遠程客戶端讀取:從讀遠程客戶端:從遠程客戶端讀取:從遠程客戶端讀取:從遠程客戶端讀取:從遠程客戶端讀取:從遠程客戶端讀取:從遠程客戶端讀取: – FarDarkMist 2014-09-22 03:06:13

相關問題