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.
| [reply] [d/l] |
In that case, use recv() or read(), instead of reading from your socket/filehandle using the <HANDLE> operator. Or, localize $_ to undef. | [reply] [d/l] |
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!? ;)
| [reply] [d/l] [select] |
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?
| [reply] |