There's really no point in reading one byte at a time. Do you mean sending? If so, check out what the Sockets FAQ has to say on this matter here. Short story: there's no guaranteed way to send data one byte at a time.
Though, I suspect from the way you've phrased your question, that what you're really want to do is read in as much as you can into a buffer, and then just process the buffer character-by-character. | [reply] |
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
| [reply] |
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] |
If you aren't interested in the gory details of sockets,
Net::Telnet might be interesting for you.
Here's an example that does what I think you want.
It doesn't read character by character, but it does
print output as it reaches the buffer, rather than
waiting for a newline:
#!/usr/bin/perl
# unbuffer STDOUT, so you can watch the
# traceroute output "realtime"
select STDOUT;$|=1;
use Net::Telnet;
my($host)="yourhost";
my($trace)="www.cnn.com";
my($username)="username";
my($passwd)="password";
my($t)=Net::Telnet->new(Host => $host);
defined($t) or die;
$t->login($username, $passwd) or die;
$t->print("traceroute $trace") or die;
while (defined($data = $t->get())) {
print $data;
# supposing your prompt is a dollar
# sign and that doesn't ever appear in
# traceroute output...
last if ($data =~ /\$/);
}
print "\n";
$t->print("exit");
$t->close;
Good luck... | [reply] [d/l] |