Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much

Zmodem and Net::Telnet

by splinky (Hermit)
on Feb 01, 2006 at 16:56 UTC ( #527113=perlquestion: print w/replies, xml ) Need Help??

splinky has asked for the wisdom of the Perl Monks concerning the following question:

I asked this same question about 9 months ago with no luck, so I thought I'd try again.

I'm communicating with another system through its serial port. It's connected to a terminal server, so to me it's a socket connection via Net::Telnet. I opened the socket manually and used Net::Telnet's fhopen, so I have the socket available to me in the main program. My program is running on a Linux box.

What I want to do is send a file via zmodem to the other system. I haven't been able to find any Perl zmodem libraries, so I tried

open2($socket, $socket, ['sz', 'myfile']);

The error I got was:

open2: close(IO::Socket::INET=GLOB(0x940d78c)) failed: Bad file descri +ptor at ./tryit line 21

Line 21 is the "open2" line.

Does anyone have any suggestions? I'd really rather not re-implement zmodem in Perl if I don't have to.


Replies are listed 'Best First'.
Re: Zmodem and Net::Telnet
by ikegami (Pope) on Feb 01, 2006 at 17:15 UTC

    What's open2? If it's from IPC::Open2, your third arg is incorrect. It shouldn't be an array ref. That's not going to fix the immediate problem, though.

    If I were to guess at the cause of your problem, I'd guess that IPC::Open3 — IPC::Open2 is just an interface to IPC::Open3 — only supports handles with a fileno, and that sockets don't have a fileno on your system.

Re: Zmodem and Net::Telnet
by sgifford (Prior) on Feb 02, 2006 at 01:19 UTC
    The problem is that open2 creates new filehandles for you to read from and write to and assigns them to the handles you pass it, instead of just using the ones you pass it. What you really want to do is more like this (which works for me):
    #!/usr/bin/perl use warnings; use strict; use IO::Socket::INET; use POSIX; my $sock = IO::Socket::INET->new(PeerHost => '', PeerPort => 9999) or die "Couldn't open socket: $!\n"; my $pid = fork; if (!defined($pid)) { die "Couldn't fork: $!\n"; } if (!$pid) { # child POSIX::close(0); POSIX::close(1); POSIX::dup2(fileno($sock),0); POSIX::dup2(fileno($sock),1); print "Running lsz $0...\n"; exec('lsz','-v',$0) or die "Couldn't run zmodem: $!\n"; } # Parent wait or die "lsz failed: $?\n"; print "lsz exited $?\n";

    Note that isn't a real system, on my system, sz is called lsz, and this script sends a copy of its own source code.

    Also, you'll want to make sure you use the appropriate options to sz and rz to make them telnet-safe; otherwise some of the characters they send could be interpreted as telnet escape sequences, which will cause you no end of grief. I use the -e and -b options for zmodem over ssh, and it usually works.

      This worked like a charm. Thanks very much.
Re: Zmodem and Net::Telnet
by samtregar (Abbot) on Feb 01, 2006 at 18:00 UTC
    Wow, zmodem! Are you sure you don't actually want ymodem-g? Back when I was file-trading on my 9600 bps modem, ymodem-g was considerably faster than zmodem. The chief advantage of zmodem, fast error-correction, doesn't apply to TCP connections like telnet which are error-free already. Some versions of ymodem even let you chat with the sysop during file-transfers!

    Ahem, where was I? Ah yes, we're in the year 2006! What the heck are you using zmodem over telnet for?

    Here's a few alternatives to consider:

    • FTP
    • SCP
    • rsync
    • Sending the file base64 encoded over the telnet link. You can decode it on the other end using Perl or a stand-alone base64 decoder. This is how stuff like Emacs' tramp-mode works for example.

    Any of these will probably be easier to implement than trying to jury-rig zmodem to transfer files via Net::Telnet.


      I thought it was clear from my question, but perhaps not -- I'm not writing code for the thing at the other end of the connection. It's a piece of equipment whose only interface is a serial port, and the only protocol it uses for file transfer is zmodem. The fact that it's on a terminal server is a convenience -- keeps us from having to physically hook a PC up to it whenever we want to do something with it.

      Unless I'm missing something, that pretty much locks me into zmodem over telnet, no matter how retarded it sounds.

Re: Zmodem and Net::Telnet
by duff (Parson) on Feb 01, 2006 at 23:47 UTC

    Assuming I understand correctly, you want to execute rz on the remote side and sz on the local side. You can do this with something similar to the spawn() routine given in the Net::Telnet docs. Here's something I just cobbled together that is fairly close to what I think should work (completely untested):

    # get the remote end ready to receive $nt->print "rz\r"; use IO::Pty (); $pty = new IO::Pty or die $!; ## Execute sz in another process. unless ($pid = fork) { # child process die "problem spawning program: $!\n" unless defined $pid; ## Disassociate process from existing controlling terminal. use POSIX (); POSIX::setsid or die "setsid failed: $!"; ## Associate process with a new controlling terminal. my $tty = $pty->slave; my $tty_fd = $tty->fileno; close $pty; ## Make stdio use the new controlling terminal. open STDIN, "<&$tty_fd" or die $!; open STDOUT, ">&$tty_fd" or die $!; open STDERR, ">&STDOUT" or die $!; close $tty; exec "sz @filenames" or die "problem executing sz\n";" }

    In any case, that's the gist of how it should work.

    update: oh, this assumes that you have sz on your end. You said the remote side was a linux box. If the local side is also linux, this should work fine. If you're running windows or something else, caveat lector! :-)

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://527113]
Approved by McDarren
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (2)
As of 2021-06-13 09:18 GMT
Find Nodes?
    Voting Booth?
    What does the "s" stand for in "perls"? (Whence perls)

    Results (54 votes). Check out past polls.