Perl:实现套接字编程(system()从不返回)

5rgfhyps  于 2022-11-15  发布在  Perl
关注(0)|答案(2)|浏览(193)

我的目标:实现套接字编程,使客户端尝试连接到服务器,如果服务器没有安装在远程机器上,客户端(主机)在其部分传输一个tar文件到服务器(目标)机器和一个Perl脚本。这个Perl脚本untar文件夹,并运行一个脚本(服务器Perl脚本),现在的问题是:此服务器脚本必须永远运行(多个客户端),直到计算机重新启动或发生意外。因此,脚本可以正常运行:但由于它是连续运行的控制不会回到客户端,客户端将再次尝试连接到服务器(在一些预定义的套接字),所以基本上我希望以某种方式运行服务器,但把控制带回我的主机,在这种情况下是客户端。
代码如下:

my $sourcedir = "$homedir/host_client/test.tar";
my $sourcedir2 = "$homedir/host_client/sabkuch.pl";
my $remote_path = "/local/home/hanmaghu";

# Main subroutines
my $ssh = Net::OpenSSH->new ( $hostmachine, user =>$username, password => $password);
$ssh->scp_put($sourcedir,$sourcedir2,$remote_path)
     or die "scp failed \n" . $ssh->error;
# test() is similar to system() in perl openssh package
my $rc = $ssh->test('perl sabkuch.pl'); 
# check if test function returned or not -> this is never executed
if ($rc == 1) {
    print "test was ok , server established \n";
}
else {
    print "return from test = $rc \n";
}
exit;

调用服务器脚本的另一个脚本是:

#!/usr/bin/perl
use strict;
use warnings;              
system('tar -xvf test.tar');
exec('cd utpsm_run_automation && perl utpsm_lts_server.pl');
#system('perl utpsm_lts_server.pl'); 
# Tried with system but in both cases it doesn't return, 
# this xxx_server.pl is my server script
exit;

服务器脚本为:

#!/usr/bin/perl

use strict;
use warnings;
use IO::Socket::INET;

#flush after every write
$| =1;

my $socket = new IO::Socket::INET (
    LocalHost => '0.0.0.0',
    LocalPort => '7783', 
    Proto => 'tcp',
    Listen => 5,
    Reuse => 1
);
die "cannot create socket $! \n" unless $socket;
print "server waiting for client on port $socket->LocalPort \n";

while (1)
{
    # waiting for new client connection
    my $client_socket = $socket->accept();

    # get info about new connected client
    my $client_address = $client_socket->peerhost();
    my $client_port = $client_socket->peerport();
    print "connection from $client_address:$client_port \n";

    # read upto 1024 characters from connected client
    my $data = "";
    $client_socket->recv($data,1024);
    print "rceeived data = $data";

    # write response data to the connected client
    $data = "ok";
    $client_socket->send($data);

    # notify client response is sent
    shutdown($client_socket,1);
}
$socket->close();

请帮助执行此操作:在设计方面,这是我想要的,但在实现时有这个问题,我能做一些其他的工作方法吗?

7fyelxc5

7fyelxc51#

简而言之,您的“驱动程序”sabkuch.pl使用exec启动服务器--它永远不会返回。
“exec”函数执行系统命令,从不返回;...
(重点来自引用的文档。)一旦使用了exec,在进程中运行的程序就会被另一个程序 * 替换 *,请参见exec wiki。如果该服务器继续运行您拥有的exit,则永远无法访问,除非出现错误。请参见上面链接的Perl的exec
因此,您的$ssh->test()将永远阻塞(直到服务器以某种方式退出)。

  • 在后台运行驱动程序
my $rc = $ssh->test('perl sabkuch.pl &');

这将启动一个单独的子shell并在其中生成sabkuch.pl,然后返回控制,test可以完成。(服务器),无限期运行。参见perlipc中的后台进程。也可以在perlfaq 8中看到它。以及那里的许多好的链接。注意,如果sabkuch.pl可以成为可执行的,就不需要perl ...

  • 看看Net::OpenSSH是否有执行命令的方法,这样它就不会阻塞。
  • “发射后不管”的一种方法是在子进程中执行fork,然后执行exec,而父进程可以做它想做的事情(在这种情况下为exit)。然后还有更多要考虑的。大量(强制)信息在X1 E4 F1 X中找到,而其他地方的例子也比比皆是(search for fork and exec)。这不应该掉以轻心,因为错误会导致奇怪的行为和无法描述的后果。下面是一个微不足道的例子。
#!/usr/bin/perl
  use strict;
  use warnings;               
  system('tar -xvf test.tar') == 0  or die "Error with system(...): $!";

  my $pid = fork;
  die "Can't fork: $!" if not defined $pid;
  # Two processes running now. For child $pid is 0, for parent large integer

  if ($pid == 0) {  # child, parent won't get into this block
      exec('cd utpsm_run_automation && perl utpsm_lts_server.pl');
      die "exec should've not returned: $!";
  }   
  # Can only be parent here since child exec-ed and can't get here. Otherwise,
  # put parent-only code in else { } and wait for child or handle $SIG{CHLD}
  # Now parent can do what it needs to...
  exit;  # in your case

通常情况下,分叉时的一个问题是wait的子项。如果我们不想这样做,可以通过 * 双重分叉 * 或处理SIGCHLD来解决请研究上面链接的perlfaq8、perlipc中的信号、所有使用的调用的文档,在这种情况下,父进程应该首先退出,然后子进程由init重新成为父进程,这样一切就都好了。艾德进程获得相同的$pid,但由于cd将触发shell(sh -c cd),因此服务器最终将使用不同的PID运行。
有了system('command &'),我们就不用担心等待孩子了。
这只与您的直接问题有关,与所示代码的其余部分无关。

h7appiyu

h7appiyu2#

我认为最好的方法是派生出一个子进程,并且存在父进程,这样子进程就可以永远运行server.pl
但是它仍然不工作,请让我知道在这个代码中我哪里出错了

#!/usr/bin/perl

use strict;
use warnings;

system('tar -xvf test.tar');

my $child_pid = fork;

if (!defined $child_pid){
      print "couldn't fork \n";}

else {
        print "in child , now executing \n";
exec('cd utpsm_run_automation && perl utpsm_lts_server.pl')
        or die "can't run server.pl in sabkuch child \n";
}

输出是我的脚本仍然挂起和打印语句“在儿童现在执行“得到运行两次,我不明白为什么,我的工作主要是汇编语言,因此这一切对我来说是新的。帮助将不胜感激。

相关问题