Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

IO::Socket tutorial

by BernieC (Pilgrim)
on Feb 17, 2020 at 15:55 UTC ( [id://11113052]=perlquestion: print w/replies, xml ) Need Help??

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

I'm converting a program that uses sockets like file descriptors {it does a <$ssh> to read a line. UGH} to using sockets properly. And I can't find a clear tutorial. I know the command to send data in my new regime is send($socket, <stuff>, flags). But I've tried to chase down what the flags are. perldoc unhelpfully just says "Takes the same flags as the system call of the same name.". First off, that seems to presume that you have a unix handy to check on the system call. Second, what I found was
$ man 2 send No manual entry for send in section 2
so I have no clue what the flags do, but the tutorials seem to all give a value of 0. ??

But my real interest in the switchover is to get reads to time out. I have a pokey host I connect to; sometimes {annoyingly regularly} the server seems to balk and my program just hangs, dead in the water, on the <$server>. So what I'd like to do is use the socket timeout mechanism to let my program continue. I see that there's a Timeout parameter that unhelpfully just says "Timeout value for various operations". ?? Units?? {I'd have guessed milliseconds, but IO::Socket says it is in seconds, which makes sense} which operations?? what happens when the timeout value is reached??

Also, my incoming data is line-at-a-time and so the <$ssh> is perfect for what I need. Is there an equivalent way to do that with IO::Socket? I guess I could recv a character at a time until I got a newline.

Replies are listed 'Best First'.
Re: IO::Socket tutorial
by haukex (Archbishop) on Feb 17, 2020 at 16:14 UTC
    First off, that seems to presume that you have a unix handy to check on the system call.

    There are lots of webpages out there to look up man pages, such as https://manpages.debian.org/buster/manpages-dev/send.2.en.html.

    No manual entry for send in section 2

    On Debian-based systems like Ubuntu, there's a package manpages-dev that contains these man pages.

    timeout mechanism

    In my experience this can be accomplished with e.g. select (the multi-arg version), or the slightly higher-level IO::Select.

    However, send and select are relatively low-level. Over time I've become more and more convinced that really the best way to do any communication with a delay is an asynchronous event-based system, of which select(2) is only the simplest. It takes a little getting used to, but it solves so many of the problems that synchronous code can suffer from that IMHO it's worth it. For example, I've used POE successfully (it has a bit of a learning curve but there's a cookbook), and recently I've been doing more with Mojolicious, and you can use its Mojo::IOLoop::Client and Mojo::IOLoop::Stream to implement a TCP client (Update: I posted an example here). If you were to show some example client code I might have the time to show what they would look like in Mojo.

      Thanks -- I'll look at POE. As for example client code, it is just unbelievably {and unfixably} dumb:
      sub command { my $cmd = "$_[0]\r\n" ; print $server $cmd ; my $resp = <$server> ; return undef if $resp !~ /^[123]/ ; return $resp ; }
      I don't even remember what got me thinking that IO::Socket's can be used as file descriptors {I just looked and can't find it in the man pages..sigh} I guess what I can do is do a 'send' with the $cmd my sub is given and then I need to replace the <$server> with something that'll timeout and then I can close/reopen the socket and try again. POE seems fancier than I need for this {although I see that it can handle the event loop of Tk, something I had trouble getting to work correctly}
        I don't even remember what got me thinking that IO::Socket's can be used as file descriptors

        Technically they can be used like handles (not descriptors), they're subclasses of IO::Handle. But as you discovered, doing a readline on them is blocking; from my experience I very much prefer non-blocking operations, and those are IMHO best abstracted via an event-based interface.

        In terms of example code, I should have been more specific: a Short, Self-Contained, Correct Example.

Re: IO::Socket tutorial
by haukex (Archbishop) on Feb 20, 2020 at 16:36 UTC

    Here's a complete example with Mojo::IOLoop and Mojo::IOLoop::Stream::Role::LineBuffer:

    mojo_serv.pl:

    #!/usr/bin/env perl use warnings; use strict; use Mojo::Util qw/dumper/; use Mojo::IOLoop; use Mojo::IOLoop::Stream::Role::LineBuffer; Mojo::IOLoop->server( { address => '127.0.0.1', port => 3000, reuse => 1 } => sub { my ($loop, $stream) = @_; my $peer = $stream->handle->peerhost.":".$stream->handle->peer +port; print "$peer: Connect\n"; $stream->timeout(30); $stream = $stream->with_roles('+LineBuffer')->watch_lines; $stream->on(read_line => sub { my ($strm, $line, $sep) = @_; print "$peer: Got line ".dumper($line); }); $stream->on(timeout => sub { print "$peer: Timeout\n" }); $stream->on(close => sub { print "$peer: Closed\n" }); $stream->on(error => sub { warn "$peer: Error: $_[1]" }); $stream->write("Hello, client from $peer.\n"); }); print "Starting server...\n"; Mojo::IOLoop->start unless Mojo::IOLoop->is_running;

    mojo_cli.pl:

    #!/usr/bin/env perl use warnings; use strict; use Mojo::Util qw/dumper/; use Mojo::IOLoop; use Mojo::IOLoop::Stream::Role::LineBuffer; Mojo::IOLoop->client( { address => '127.0.0.1', port => 3000 } => sub { my ($loop, $err, $stream) = @_; if (defined $err) { warn "Error: $err"; return } print "Connect\n"; $stream->timeout(10); $stream = $stream->with_roles('+LineBuffer')->watch_lines; $stream->on(read_line => sub { my ($strm, $line, $sep) = @_; print "Got line ".dumper($line); }); $stream->on(timeout => sub { print "Timeout\n" }); $stream->on(close => sub { print "Closed\n" }); $stream->on(error => sub { warn "Error: $_[1]" }); $stream->write("Hello, server, I am a client.\n"); }); print "Starting client...\n"; Mojo::IOLoop->start unless Mojo::IOLoop->is_running;

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11113052]
Approved by cavac
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (5)
As of 2024-04-25 15:14 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found