hyadijxp 发表于 2018-8-31 06:33:59

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

  #!/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=;
  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})
  {
  if ($userslist{$un_pass} eq $un_pass)
  {
  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=;
  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})
  {
  if ($userslist{$un_pass} eq $un_pass)
  {
  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 || '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=;
  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})
  {
  if ($userslist{$un_pass} eq $un_pass)
  {
  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 ne "encrypt")
  {
  syswrite($session,"unknow\n");
  close($session);
  exit;
  }
  if ($ifen == 0)
  {
  $enback = "encrypt:ok";
  }else{
  if ($tmp == 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;
  }
  sub receive_client_pubkey #接收并保存客户端的公钥
  {
  my $clientpubkey;
  while (1)
  {
  sysread($session,$clientpubkey,1096);
  if ($clientpubkey =~ /pub:.*/gi)
  {
  my @tmp =split(":",$clientpubkey);
  $ck{$tmp} = $tmp;
  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 || '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 ne "ok")
  {
  print "Server Force Encryption!\n";
  exit 0;
  }
  }
  sub send_pub_key
  {
  $rsa = new Crypt::RSA;
  ($public, $private) =
  $rsa->keygen (
  Identity=> 'Lord Macbeth ',
  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=;
  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);

页: [1]
查看完整版本: Perl Socket 通信recv超时退出子进程