设为首页 收藏本站
查看: 816|回复: 0

[经验分享] Perl Socket 通信recv超时退出子进程

[复制链接]

尚未签到

发表于 2018-8-31 06:33:59 | 显示全部楼层 |阅读模式
  #!/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[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=;
  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=;
  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 ',
  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、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-559022-1-1.html 上篇帖子: perl中调用recv函数阻塞,设置超时 下篇帖子: Perl多进程实战
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表