Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer

Net::SSH2 command output polling

by VinsWorldcom (Parson)
on Oct 12, 2012 at 12:38 UTC ( #998671=perlquestion: print w/replies, xml ) Need Help??
VinsWorldcom has asked for the wisdom of the Perl Monks concerning the following question:

I have yet another Net::SSH2 question that I haven't found a definitive solution to yet. So here goes.


Windows 7 x64 / Strawberry Perl 5.16.1 / Net::SSH2 0.45 - note that Net::SSH2 comes bundled with Strawberry, I did not compile myself.

I've created a simple SSH client using Net::SSH2 and I can connect fine, I've gotten past the freezing issue on Windows ($chan->blocking(0)) and even the issue where the command output lagged one command behind (binmode($chan)), but only sometimes.

I'm testing my client to both CentOS and Cisco router with SSH enabled.


The issue I see is that if I execute a long command (e.g., 'ls -alR /' on linux, 'show run' on Cisco router) I start to see some output and then just get the prompt back. When I issue the next command, I get the remainder of output from the first long command - or maybe just some of it if it's a really long output.

To my novice mind, it seems to be a buffering problem and I've tried the flush() method of Net::SSH2 to no avail. My other thought is that I need to set $| on the $chan filehandle, which also didn't solve it. My final desperation was to actually read the POD line-by-line and found the poll() method and some Google-ing turned up an example of it's usage.

I tried:

my @poll = ({handle => $chan, events => 'in'}); if($ssh2->poll(250, \@poll) && $poll[0]->{revents}->{in}) { print $buf while defined ($len = $chan->read($buf,512)) }

and in a last ditch attempt:

my ($rin, $rout, $ein, $eout) = ('', '', '', ''); vec($rin, $chan, 1) = 1; # tried $ssh2 and $chan, # but should be: fileno($var) which errors if (select($rout=$rin, undef, $eout=$ein, 5000)) { print $buf while defined ($len = $chan->read($buf,512)) }

Neither above command set fixed the issue.


I'm now thinking it may be due to blocking(0); however, if that isnt' used, Windows just hangs after the connect. How can I get Net::SSH2 to "wait" until all output from a command is printed without just adding an artificially long sleep? Note that I use Net::Telnet to connect to linux and Cisco routers and this isn't an issue - it patiently waits until all output is printed and never seems to chop command output (which I think is the buffering issue).


#!/usr/bin/perl use strict; use warnings; use Net::SSH2; use Term::ReadLine; my $host = ''; my $user = 'cisco'; my $pass = 'cisco'; my ($len, $buf); my $ssh2 = Net::SSH2->new(); if ($ssh2->connect($host)) { print "[Connected]\n"; if ($ssh2->auth_password($user, $pass)) { print "[Authenticated]\n"; # Set up shell for interactive my $chan = $ssh2->channel(); $chan->blocking(0); # Needed on Windows $chan->shell(); #binmode($chan); # Seems to take care of both Unix SSH and Cis +co servers # Sometimes needed to "clear", flush() doesn't seem to work # Otherwise, first command does not work select(undef,undef,undef,0.2); # or sleep 1 print $buf while defined ($len = $chan->read($buf,512)); # START: Interactive Mode my $prompt = "ssh> "; my $ssh = Term::ReadLine->new("SSH"); $ssh->ornaments(0); while (defined (my $cmd = $ssh->readline($prompt))) { chomp $cmd; if ($cmd =~ /^\s*$/) { next } # nothing if ($cmd =~ /^\s*exit\s*$/) { last } # exit $chan->write("$cmd\n"); select(undef,undef,undef,0.2); # or sleep 1 print $buf while defined ($len = $chan->read($buf,512)) } # END: Interactive Mode $chan->close } else { warn "Authentication failed\n" } } else { warn "Unable to connect to host $host: $!\n" }

Replies are listed 'Best First'.
Re: Net::SSH2 command output polling
by t_rex_joe (Acolyte) on Oct 12, 2012 at 18:39 UTC
    Honestly I've always used "Net::SSH::Perl" module.
    Found the interaction with TTY/PTYs to be less
    troublesome. Not to mention retrieving large
    amounts of "sh arp" and "sh cam dyn" from IOS/CATOS 
    Here's a sample I use from my script for logging in.
      $ssh = Net::SSH::Expect->new(
              host => $ip, 
              user => $suser,
              password => $spass,
              timeout => 3,
              log_file => "$ofdir/$stime.$bname.$ip.dump_out.$^T.txt",
              raw_pty => 1);
      $ok = $ssh->run_ssh();
      if(!(defined $ok) || ($ok eq "")) { $ok = 0; } else { $ok = 1; }
      if($debug == 1) { print "$meth... "; }
      $ok = $ssh->waitfor('key verification failed', 5);
      if((!$ok) || ($ok eq "")) { $ok = 0; }
      if($ok == 1) { if($debug == 1 ) { print "FOUND ERROR ID KEY FAILED\n"; } $fpssh = 1; }
       else { if($debug == 1) { print "DID NOT FIND.. CONTINUE\n"; } $fpssh = 0; } $ok = 0;
      if($fpssh == 1)
        if($debug == 1) { print "FOUND host key failed PROMPT\n"; }
        $val = "host_key_failed_prompt";
        } #EO if($fpssh == 1)
        $meth = "FIND #";
        if($debug == 1) { print "$meth... "; }
        $ok = $ssh->waitfor('#', 30, -re);
        if((!$ok) || ($ok eq "")) { $ok = 0; }
        if($ok == 1) { if($debug == 1) { print "GO\n"; } $fppt = 1; }
         else { if($debug == 1) { print "ERROR\n"; } $fppt = 0; } $ok = 0;
        if($fppt != 1)
          $val = "did_not_find_en_prompt";
          } #EO if($fpps == 1)
        $meth = "SEND SH ARP";
        if($debug == 1) { print "$meth... \n"; }
        if($debug == 1) { print "GO\n"; }
        while(defined ($line = $ssh->read_line()))
          if(!(defined $line) || ($line eq "")) { next; }
          if($debug == 1) { print "LINE: \"" . __LINE__ . "\" LINE: \"$line\"\n"; }
          push @outs, $line;
    To show the current buffer from the script incase
    of problems using "expect" like interactions..
        if($debug == 1) { print "PEEK: \"" . $ssh->peek(0) . "\" L: \"" . __LINE__ . "\"\n"; }
    -- Notice the line "while(defined ($line = $ssh->read_line()))". 
    This is different from the original line in the
    documentation of "@outs = $ssh->waitfor('#', -re, 30);"
    the "read line" is more fault tolerant.
    -- I make sure each module (login, run command, exit)
    is their own section of code, having nested if statements
    is bad if your are using "parallel fork manager" and if 
    you have to exit/next in the middle of the script.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://998671]
Approved by BrowserUk
[1nickt]: choroba Is it a safe assumption that if there is a threaded perl then the user will want to use Thread::Queue?
[hippo]: Why not?
[1nickt]: That's good! I suppose the cpanfile would be the same however the app distro is structured ...
[1nickt]: hippo no reason why not other than wanting to check an assumption :-)
[hippo]: For a self-contained application which can therefore ensure thread safety it seems like a sensible approach.

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (19)
As of 2017-10-18 13:14 GMT
Find Nodes?
    Voting Booth?
    My fridge is mostly full of:

    Results (244 votes). Check out past polls.