Perl Socket 通信recv超时退出子进程

来源:互联网 发布:狗笼子淘宝 编辑:程序博客网 时间:2024/06/05 15:04

#!/usr/bin/perl
#server
use strict;
use Socket;
use IO::Handle;
use POSIX ":sys_wait_h";


my($this, $now);
my $port = shift || 29688;
my $address=inet_aton("0.0.0.0");
$this =sockaddr_in($port,$address); #pack('Sna4x8', AF_INET, $port, "\0\0\0\0");
print "Port = $port\n";
my $prototype = getprotobyname('tcp');
socket(SOCKET, PF_INET, SOCK_STREAM, $prototype) || die "socket: $!\n";
print "Socket ok.\n";
bind(SOCKET, $this) || die "bind: $!\n";
print "Bind ok.\n";
listen(SOCKET, SOMAXCONN) || die "connect: $!\n";
print "Listen ok.\n";
SOCKET->autoflush;

while(1){
print "In loop.\n";
accept(CLIENT, SOCKET) || die "$!\n";
CLIENT->autoflush;
print "Accept ok.\n";
while(waitpid(-1,WNOHANG)>0){}

my $pid = fork(); #有远程访问就fork子进程处理
CLIENT->autoflush;
if (not defined $pid) {
print CLIENT "resources not avilable.\n";
close(CLIENT);
}elsif ($pid == 0) {
print "\nfork pid:$pid\n";
CLIENT->autoflush;
while(1)
{
my $c = '';
print "what happened";
sysread(CLIENT, $c, 100) or die "recv: $!";
print "\nclient say:$c\n";
if ($c =~ /quit/gi)
{
close(CLIENT);
exit;
}
syswrite(CLIENT, $c."back\n",100);
}
print "\npid:$pid\n";
}
close(SOCKET);
-----------------------------------------------------------------
#!/usr/bin/perl
#client.pl
require 5.6.0.0;
#use strict;
use Socket;
#use FileHandle;
use IO::Handle;

my($remote, $port, @thataddr, $that,$them, $proto,@now);
$remote = "vps.9588.org"; #shift || 'localhost' ;
$port = 29688 ;
@thataddr=gethostbyname($remote);
my $address=inet_aton("$remote");
$that =sockaddr_in($port,$address);
$proto = getprotobyname('tcp');
# Make the socket filehandle
if ( socket(SOCK, PF_INET, SOCK_STREAM, $proto ) ){
print "Socket ok.\n";
}
else { die $!; }
if (! connect(SOCK, $that)) {
print "Connect error.\n";
}
else{
print "Connect ok.\n";
while (1){
print "\nPlease input:";
$msg_out=<STDIN>;
if ($msg_out eq "\n"){next;}
#if ($msg_out!~ /cd|touch/gi ){recv (SOCK,$msg_in,2048,0);}
if ($msg_out=~/quit/i)
{
syswrite(SOCK,"I will quit,bye!",100);
close(SOCK);
exit 0;
}
syswrite(SOCK,$msg_out,100);
sysread(SOCK,$msg_in,100);
print "Server result:$msg_in\n";
}
}
close(SOCK);


-----------------------------------------------------------------
-----------------------------------------------------------------

这个带了认证和超时自动断开链接
#!/usr/bin/perl
#server
use strict;
use Socket;
use IO::Handle;
use POSIX ":sys_wait_h";


sub auth
{
my %userslist =(
   "edwinzhou" => "123456",
   "test" => "test"
);
my $getstr = "";
my $authfail = 0;
sysread(CLIENT, $getstr,30);
chomp($getstr);
if ($getstr =~ /auth/gi && $getstr =~ /:/gi)
{
   my @un_pass = split(":",$getstr);
   if (defined $userslist{$un_pass[1]})
   {
      if ($userslist{$un_pass[1]} eq $un_pass[2])
      {
         syswrite(CLIENT,"auth:ok");
         return "ok";
      }else{$authfail = 1;}
   }else{$authfail = 1;}
}else{$authfail = 1;}

if ($authfail == 1)
{
    print "auth:fail\n";
    syswrite(CLIENT,"auth:fail");
    close(CLIENT);
}
}

sub cleardp
{
while(waitpid(-1,WNOHANG)>0){}
}

sub settimeout #定义ALRM发生信号时的操作,这里发信给客户端并断开链接,子进程退出
{
$SIG{ALRM} = sub {
print "recv timeout\n";
syswrite(CLIENT,"timeout");
close(CLIENT);
exit;
};
}

my($this, $now);
my $port = shift || 29688;
my $address=inet_aton("0.0.0.0");
$this =sockaddr_in($port,$address); #pack('Sna4x8', AF_INET, $port, "\0\0\0\0");
print "Port = $port\n";
my $prototype = getprotobyname('tcp');
socket(SOCKET, PF_INET, SOCK_STREAM, $prototype) || die "socket: $!\n";
print "Socket ok.\n";
bind(SOCKET, $this) || die "bind: $!\n";
print "Bind ok.\n";
listen(SOCKET, SOMAXCONN) || die "connect: $!\n";
print "Listen ok.\n";
SOCKET->autoflush;
while(1){
print "In loop.\n";
accept(CLIENT, SOCKET) || die "$!\n";
CLIENT->autoflush;
print "Accept ok.\n";
cleardp();
#$SIG{ALRM} = {}; #网上有的地方说是必须的,不过好像不加也可以

my $pid = fork();
CLIENT->autoflush;
if (not defined $pid) {
print CLIENT "resources not avilable.\n";
close(CLIENT);
}elsif ($pid == 0) {
print "\nfork pid:$pid\n";
CLIENT->autoflush;
my $c = "";
settimeout(); #调用定义ALARM子例程
alarm( 10 );
my $authresult = auth(); #在中间的这段,如果大于10秒还没有完成,就调用ALARM中定义的操作
alarm( 0 );
print "\nauthresult:$authresult\n";
exit if $authresult ne "ok";
while(1)
{
alarm( 10 ); #同上,一般放在会超时的操作代码
sysread(CLIENT, $c, 100); #or die "recv: $!";
alarm( 0 );
chomp($c);
print "\nclient say:$c\n";
if ($c =~ /quit/gi)
{
close(CLIENT);
exit;
}
syswrite(CLIENT, $c."back\n",100);
}
print "\npid:$pid\n";
}
}
---------------------------------------------------------------
#!/usr/bin/perl
#client.pl
require 5.6.0.0;
#use strict;
use Socket;
#use FileHandle;
use IO::Handle;

my($remote, $port, @thataddr, $that,$them, $proto,@now);
$remote = shift || 'localhost' ;
$port = 29688 ;
@thataddr=gethostbyname($remote);
my $address=inet_aton("$remote");
$that =sockaddr_in($port,$address);
$proto = getprotobyname('tcp');
# Make the socket filehandle
if ( socket(SOCK, PF_INET, SOCK_STREAM, $proto ) ){
print "Socket ok.\n";
}
else { die $!; }
if (! connect(SOCK, $that)) {
print "Connect error.\n";
}
else{
print "Connect ok.\n";


while (1){
print "\nPlease input:";
$msg_out=<STDIN>;
if ($msg_out eq "\n"){next;}
#if ($msg_out!~ /cd|touch/gi ){recv (SOCK,$msg_in,2048,0);}
if ($msg_out=~/quit/i)
{
syswrite(SOCK,"I will quit,bye!",100);
close(SOCK);
exit 0;
}
syswrite(SOCK,$msg_out,100);
sysread(SOCK,$msg_in,100);
if ($msg_in =~ /auth:fail/gi)
{
   print "login fail...";
   close(SOCK);
   exit 0;
}

print "Server result:$msg_in\n";
}
}
close(SOCK);

--------------------------------------------------------------
--------------------------------------------------------------

利用IO::Socket模块的方法,功能同上,可以在超时时间到达后回收子进程
#server
#!/usr/bin/perl
use strict;
use IO::Socket;
use IO::Socket 'sockatmark';
use POSIX ":sys_wait_h","WNOHANG";

my $session;

sub cleardp
{
while(waitpid(-1,WNOHANG)>0){}
}

sub auth
{
my %userslist =(
   "edwinzhou" => "123456",
   "test" => "test"
);
my $getstr = "";
my $authfail = 0;
sysread($session, $getstr,30);
chomp($getstr);
if ($getstr =~ /auth/gi && $getstr =~ /:/gi)
{
   my @un_pass = split(":",$getstr);
   if (defined $userslist{$un_pass[1]})
   {
      if ($userslist{$un_pass[1]} eq $un_pass[2])
      {
         syswrite($session,"auth:ok\n");
         return "ok";
      }else{$authfail = 1;}
   }else{$authfail = 1;}
}else{$authfail = 1;}

if ($authfail == 1)
{
    print "auth:fail\n";
    syswrite($session,"auth:fail\n");
    close($session);
}
}

sub settimeout
{
$SIG{ALRM} = sub {
print "recv timeout\n";
syswrite($session,"timeout\n");
close($session);
exit;
};
}

my $port      = $ARGV[0] || '29688';
my $sock = IO::Socket::INET->new( Listen     => 20,
                                   LocalPort => $port,
                                   Timeout    => 20*1,
                                   Reuse      => 1)
  or die "Can't create listening socket: $!\n";


while (1) {
     cleardp();
     print "Listening...\n";
     next unless $session = $sock->accept;
     defined (my $pid = fork) or die "Can't fork: $!\n";
     if($pid == 0) {

$session->autoflush(1);
my $c;
settimeout();
alarm( 120 );
my $authresult = auth();
alarm( 0 );
print "\nauthresult:$authresult\n";
exit if $authresult ne "ok";
while (1)
{
alarm( 20 );
sysread($session,$c,100); #|| die "error:$!\n";
alarm( 0 );
chomp($c);
print "client say:$c\n";
if ($c =~ /quit/gi)
{
close($session);
exit;
}
syswrite($session,$c,100);
}
}else
{
print "Forking child $pid\n";
}
}
--------------------------------------------------------------
--------------------------------------------------------------
perl socket,远程shell例子,还有点Bug
#!/usr/bin/perl
#server.pl
#my $prototype = getprotobyname('tcp');
#print $prototype,"\n";
#print SOMAXCONN;
require 5.6.0.0;
#use strict;
use Socket;
#use FileHandle;
use IO::Handle;
use POSIX ":sys_wait_h";

my($this, $now);
my $port = shift || 29688;
my $address=inet_aton("0.0.0.0");
$this =sockaddr_in($port,$address); #pack('Sna4x8', AF_INET, $port, "\0\0\0\0");
print "Port = $port\n";
my $prototype = getprotobyname('tcp');
socket(SOCKET, PF_INET, SOCK_STREAM, $prototype) || die "socket: $!\n";
print "Socket ok.\n";
bind(SOCKET, $this) || die "bind: $!\n";
print "Bind ok.\n";
listen(SOCKET, SOMAXCONN) || die "connect: $!\n";
print "Listen ok.\n";
SOCKET->autoflush;

while(1){
print "In loop.\n";
accept(CLIENT, SOCKET) || die "$!\n";
CLIENT->autoflush;
print "Accept ok.\n";
while(waitpid(-1,WNOHANG)>0){}

my $pid = fork();
if (not defined $pid) {
print CLIENT "resources not avilable.\n";
close(CLIENT);
}elsif ($pid == 0) {
print "\nfork pid:$pid";
open(STDIN, ">&CLIENT");
open(STDOUT, ">&CLIENT");
open(STDERR, ">&CLIENT");
system("/bin/sh");
close(STDIN);
close(STDOUT);
close(STDERR);
close(CLIENT);
exit 0
}
print "\npid:$pid";
}
close(SOCKET);
----------------------------------------------------------------------
#!/usr/bin/perl
#client.pl
require 5.6.0.0;
#use strict;
use Socket;
#use FileHandle;
use IO::Handle;

my($remote, $port, @thataddr, $that,$them, $proto,@now);
$remote = shift || 'localhost' ;
$port = 29688 ;
@thataddr=gethostbyname($remote);
my $address=inet_aton("$remote");
$that =sockaddr_in($port,$address);
$proto = getprotobyname('tcp');
# Make the socket filehandle
if ( socket(SOCK, PF_INET, SOCK_STREAM, $proto ) ){
print "Socket ok.\n";
}
else { die $!; }
if (! connect(SOCK, $that)) {
print "Connect error.\n";
}
else{
print "Connect ok.\n";
while (1){
print "\nPlease input:";
$msg_out=<STDIN>;
if ($msg_out eq "\n"){next;}
send(SOCK,$msg_out,0);
if ($msg_out!~ /cd|touch/gi ){recv (SOCK,$msg_in,2048,0);}
exit if $msg_out=~/quit/i;
print "Server result:$msg_in\n";
}
}
close(SOCK);


--------------------------------------------------------------
--------------------------------------------------------------
Crypt::RSA 对通讯进行加密传输
#!/usr/bin/perl
use strict;
use IO::Socket;
use IO::Socket 'sockatmark';
use POSIX ":sys_wait_h","WNOHANG";
use Crypt::RSA;

my $session;
my $ifen = 1; #定义服务端是否需要强制加密 1-是 0否
my %ck; #定义散列,用来存放客户端传来的公钥 :应该定义在子进程中,以后改
my $rsa = new Crypt::RSA;
my $p_pubkey;


sub cleardp
{
    while(waitpid(-1,WNOHANG)>0){}
}

sub auth
{
    my %userslist =(
       "edwinzhou" => "123456",
       "test" => "test");
    my $getstr = "";
    my $authfail = 0;
    sysread($session, $getstr,30);
    chomp($getstr);
    if ($getstr =~ /auth/gi && $getstr =~ /:/gi)
    {
       my @un_pass = split(":",$getstr);
       if (defined $userslist{$un_pass[1]})
       {
          if ($userslist{$un_pass[1]} eq $un_pass[2])
          {
             syswrite($session,"auth:ok\n");
             return "ok";
          }else{$authfail = 1;}
       }else{$authfail = 1;}
    }else{$authfail = 1;}

    if ($authfail == 1)
    {
        print "auth:fail\n";
        syswrite($session,"auth:fail\n");
        close($session);
    }
}

sub settimeout
{
    $SIG{ALRM} = sub {
        print "recv timeout\n";
        syswrite($session,"timeout\n");
        close($session);
        exit;
    };
}

sub consult  #和客户端协商是否使用加密
{
    my $enback;
    sysread($session,my $msgread,15);
    my @tmp = split(":",$msgread);
    if ($tmp[0] ne "encrypt")
    {
       syswrite($session,"unknow\n");
       close($session);
       exit;
    }
    if ($ifen == 0)
    {
       $enback = "encrypt:ok";
    }else{
       if ($tmp[1] == 0)
       {
          $enback = "encrypt:fail";
          syswrite($session,$enback,length($enback));
          close($session);
          exit;
       }else{
          $enback = "encrypt:ok";
       }
    }
    print "result:$enback\n";
    syswrite($session,$enback,length($enback));
    return $tmp[1];
}

sub receive_client_pubkey #接收并保存客户端的公钥
{
    my $clientpubkey;
    while (1)
    {
        sysread($session,$clientpubkey,1096);
        if ($clientpubkey =~ /pub:.*/gi)
        {
           my @tmp =split(":",$clientpubkey);
           $ck{$tmp[1]} = $tmp[2];
           syswrite($session,"pubrevok",length("pubrevok"));
        }
        elsif ($clientpubkey eq "pubsendover")
        {
           last;
        }
        else
        {
           syswrite($session,"pub:unknow",length("pub:unknow"));
           close($session);
           exit;
        }
    }
    foreach my $eachkey (keys(%ck))
    {
       print "$eachkey:",$ck{$eachkey},"\n";
    }
}

sub encrypt($)
{
    my $message = shift;
    $p_pubkey = bless(\%ck,'Crypt::RSA::Key::Public'); #组合
    #print "zhizhen:",$p_pubkey,"\n";
    my $cyphertext =
            $rsa->encrypt (
                Message    => $message,
                Key        => $p_pubkey,
                Armour     => 1
            ) || die "encrypt error:",$rsa->errstr();
    print "encrypted:$cyphertext\n";
    return $cyphertext;
}


my $port      = $ARGV[0] || '29688';
my $sock = IO::Socket::INET->new( Listen     => 20,
                                   LocalPort => $port,
                                   Timeout    => 20*1,
                                   Reuse      => 1)
  or die "Can't create listening socket: $!\n";


while (1) {
     cleardp();
     print "Listening...\n";
     next unless $session = $sock->accept;
     defined (my $pid = fork) or die "Can't fork: $!\n";
     if ($pid == 0)
     {
        $session->autoflush(1);
        my $c;
        settimeout();
        my $clientifen = consult();
        if ($clientifen == 0)
        {
           print "client didn't need encrypt\n";
        }else{
           print "client need encrypt\n";
           receive_client_pubkey();
           my $hello = "hello";
           my $encryptstr = encrypt($hello);
           syswrite($session,$encryptstr,length($encryptstr));
        }
       alarm( 120 );
       my $authresult = auth();
       alarm( 0 );
       print "\nauthresult:$authresult\n";
       exit if $authresult ne "ok";
       while (1)
       {
             alarm( 20 );
             sysread($session,$c,100) || die "error:$!\n";
             alarm( 0 );
             chomp($c);
             print "client say:$c\n";
             if ($c =~ /quit/gi)
             {
                close($session);
                exit;
             }
             syswrite($session,$c,100);
       }
     }else
      {
             print "Forking child $pid\n";
      }
}
--------------------------------------------------------------

#!/usr/bin/perl
#client.pl
require 5.6.0.0;
#use strict;
use Socket;
#use FileHandle;
use IO::Handle;
use Crypt::RSA;

my $rsa;
my ($public, $private);

sub consult($)
{
    my $ifen = shift;
    my $msg = "encrypt:$ifen";
    my $msgread;
    syswrite(SOCK,$msg,length($msg));
    sysread(SOCK,$msgread,15);
    my @tmp = split(":",$msgread);
    if ($tmp[1] ne "ok")
    {
        print "Server Force Encryption!\n";
        exit 0;
    }
}

sub send_pub_key
{
    $rsa = new Crypt::RSA;
    ($public, $private) =
           $rsa->keygen (
              Identity  => 'Lord Macbeth <macbeth@glamis.com>',
              Size      => 1024, 
              Password  => 'A day so foul & fair',
              Verbosity => 1,
          ) or die $rsa->errstr();
    my @tmp = split("=",$public);
    foreach my $eachkey (keys(%$public))
    {
         my $sendpub = "";
         my $msgin;
         $sendpub = "pub:$eachkey:".%$public->{$eachkey};
         print "$eachkey:".%$public->{$eachkey}."\n";
         syswrite(SOCK,$sendpub,length($sendpub));
         sysread(SOCK,$msgin,10);
         if ($msgin ne "pubrevok")
         {
            return 0;
         }
    }
    syswrite(SOCK,"pubsendover",length("pubsendover"));
    return 1;
}

sub encrypt
{
    my $message = "hello";
    print "public:$public\n";
    my $cyphertext =
           $rsa->encrypt (
               Message    => $message,
               Key        => $public,
               Armour     => 1,
           ) || die $rsa->errstr();
    return $cyphertext;
}

sub decrypt
{
    my $enstr = shift;
    my $plaintext =
          $rsa->decrypt (
               Cyphertext => $enstr,
               Key        => $private,
               Armour     => 1,
          ) || die $rsa->errstr();
    return $plaintext;
}

my($remote, $port, @thataddr, $that,$them, $proto,@now);
$remote = shift || 'localhost' ;
$port = 29688 ;
@thataddr=gethostbyname($remote);
my $address=inet_aton("$remote");
$that =sockaddr_in($port,$address);
$proto = getprotobyname('tcp');
if ( socket(SOCK, PF_INET, SOCK_STREAM, $proto ) ){
print "Socket ok.\n";
}
else { die $!; }
if (! connect(SOCK, $that)) {
print "Connect error.\n";
}
else{
print "Connect ok.\n";

my $ifencryption = 1;
consult($ifencryption);
if ($ifencryption == 1)
{
   my $sendkey_result = send_pub_key();
   if ($sendkey_result == 1)
   {
      sysread(SOCK,my $msg,500);
      print $msg,"\n";
      my $destr = decrypt($msg);
      print $destr,"\n";
   }
   else
   {
      print "send key error\n";
      close(SOCK);
      exit 0;
   }
}

while (1){
print "\nPlease input:";
$msg_out=<STDIN>;
if ($msg_out eq "\n"){next;}
if ($msg_out=~/quit/i)
{
syswrite(SOCK,"I will quit,bye!",100);
close(SOCK);
exit 0;
}
syswrite(SOCK,$msg_out,100);
sysread(SOCK,$msg_in,100);
print "error:$!\n";
if ($msg_in =~ /auth:fail/gi)
{
   print "login fail...";
   close(SOCK);
   exit 0;
}
chomp($msg_in);
print "Server result:$msg_in\n";
}
}
close(SOCK);