Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Re: Re: how do I read from a socket one byte at a time?

by reyjrar (Hermit)
on Jan 25, 2001 at 02:57 UTC ( [id://54146]=note: print w/replies, xml ) Need Help??


in reply to Re: how do I read from a socket one byte at a time?
in thread how do I read from a socket one byte at a time?

actually, I guess I wasn't very clear..
what I want to do is read from the socket realtime parsing data as its sent not waiting for the "\n" to be able to process that line..

hrm.. does that make sense? basically what I'm trying to simulate here is a "telnet host; traceroute otherhost" and see the little "*" or the hops REALTIME.. not wait for 3 timeouts on each little "*" to process the line. this isn't exactly what I'm doing I'm interacting with a program that writes unbuffered to a handle, but it appears that somewhere the sockets I'm creating are not allowing me to read from them unbuffered like telnet or ssh sessions would..

-brad.. looking at Expect.pm
  • Comment on Re: Re: how do I read from a socket one byte at a time?

Replies are listed 'Best First'.
Re: Re: Re: how do I read from a socket one byte at a time?
by tadman (Prior) on Jan 25, 2001 at 05:01 UTC
    You would certainly want to employ select() and read() instead of your usual filehandle methods (i.e. '<F>') which block until a linefeed, or the value in $/ if it is set to something else, is received.

    The select() function lets you know when there's something to read, which means you can do something else while you're waiting, such as time-out if nothing happens.

    This program should give you the data as it comes in from a socket:
    #!/usr/bin/perl -w use strict; use IO::Socket; my ($host) = "www.perlmonks.org"; my ($port) = "http(80)"; my ($socket) = new IO::Socket::INET (PeerAddr => $host, PeerPort => $port, Proto => 'tcp'); die "Can't connect to $host:$port\n" unless $socket; my ($rfd) = ''; # Must be initialized by string, # not numeric my ($timeout) = 5.0; # 5s timeout my ($block_size) = 10_000_000; # Buffer "size" at ~10MB $|++; # Unbuffer STDOUT # Send a sample transaction via HTTP $socket->write ("GET / HTTP/1.0\r\nHost: $host\r\n\r\n"); $socket->flush(); # Wait loop to receive content while (1) { # Set the bit-flag for the socket you are waiting on = 1 vec ($rfd, $socket->fileno(), 1) = 1; # Wait for something to happen if (select ($rfd, undef, undef, $timeout) >= 0 && vec($rfd, $socket->fileno(), 1)) { # Something came in! my ($buffer); # Check what it is by calling read() on the socket my ($result) = $socket->read ($buffer, $block_size); # Print out what came in print $buffer; # Drop out of the loop if read() returns a zero # value, indicating EOF. last unless $result; } else { # Timed out on the select(), so bail out. last; } }
    I haven't used IO::Socket much, so this was interesting practice. Normally, I just use Socket, which is a far sight better than the Perl4 method using pack(). Hash-style named parameters are all the rage these days, and I'm not complaining. I really should port all my stuff over as soon as I can.

    Additionally, you can set the timeout parameter of the select() call to be 0 which means that select() will return immediately, without waiting. This is useful if you need to check if some new data has arrived, but have better things to do than wait around for it.
Re: Re: Re: how do I read from a socket one byte at a time?
by MeowChow (Vicar) on Jan 25, 2001 at 03:07 UTC
    In that case, use recv() or read(), instead of reading from your socket/filehandle using the <HANDLE> operator. Or, localize $_ to undef.
      I've been using recv, haven't tried read yet. I actually tend to stray away from <SOCKET> and print SOCKET because I've read that they block. using send/recv and setting the length to 1 didn't work, because recv "expands or contracts the length of $var to the length actually read from the handle" which for some reason even with an autoflush on the socket is everything up to the newline character. read and sysread do the same thing.. do I need to use vectors and the 4 arg select to accomplish this?

      -brad.. this sounds SO simple, so WHY ISN'T IT!? ;)
        Yes, they do indeed block, but it sounds like blocking semantics are what you are looking for. Writing non-blocking code is a non-trivial task (especially if you want cross-platform compatibility).

        If you did indeed fcntl the socket to O_NONBLOCK, then yes, it would be good form to use select (or IO::Select), in order to determine whether or not data is present for recv, though this is not technically required, as a recv call will return EAGAIN on a non-blocking socket, if there is no data present to be received.

        You also seem to be confusing buffered/unbuffered with blocking/non-blocking. Using send and recv (as well as sysread and syswrite, but not read and print) means that you are using unbuffered IO. Changing the value of autoflush has no effect on recv and send.

        Regarding the resizing of your scalar, it should only be resized up to the maximum size specified in your recv call. Why don't you post your code so we can get a better idea of what's happening?

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://54146]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others sharing their wisdom with the Monastery: (4)
As of 2024-04-20 02:08 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found