Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Re: Getting Data from server

by pjf (Curate)
on Oct 04, 2001 at 05:18 UTC ( [id://116618]=note: print w/replies, xml ) Need Help??


in reply to Getting Data from server

G'day shadox,

When you say, "it doesn't do anything", does that really mean "it hangs forever?". If so, I suspect that I know what the problem is.

If your socket is in the (default) blocking mode, your process will block waiting for data whenever you try to read from the socket. If there is a line waiting for you, or one is just about to arrive, then this works wonderfully. However, if you try to read when the remote end isn't intending on sending you anything, your process will sit there waiting for data that will never arrive.

You've got a few options here. Probably the best way of solving things is to look at the data you've received and determine if you're expecting any more. So if you know that every response from the client will end with a "GO AHEAD" you can do something like this:

my $buffer = <$sock>; while ($buffer !~ /GO AHEAD\Z/) { $buffer .= <$sock>; }
Of course, the catch here is that if the remote end doesn't terminate its response as you expect, you're left blocking on the socket forever.

Your second option is to use some sort of timeout, possibly in conjunction with the terminator matching code above. If we're expecting another line, we wait for one to arrive, but we don't block indefinitely. select() is a good way to wait for data to arrive, but allowing you to get out cleanly if it takes too long.

The problem with select is that it doesn't play nicely with buffered I/O, which is what <$socket> gives you. Instead, you'll have to use low-level functions like sysread. This isn't much harder. I'd strongly recommend using IO::Select rather than the core select() call, for sanity reasons:

use IO::Socket; use POSIX qw/BUFSIZ/; # Create an IO::Select object, and ask it to look at $sock. my $s = IO::Select->new(); $s->add($sock); # Continue to read on $sock until things are quiet for # at least one second. my $message; while ($s->can_read(1)) { my $buffer; my $bytes_read = sysread($sock,$buffer,BUFSIZ); unless ($bytes_read) { # Socket just closed, clean it up... } $message .= $buffer; }
Select can be used to examine multiple filehandles and determine which one(s) are available for reading. See the IO::Select manpage for details.

The downside of using select like this is that your process will be spending a second at the end of each message waiting for data that isn't there, or it could miss data in caes of high lag where it takes longer than a second for packets to arrive.

I would personally recommend using the first method of determining when more data is due to arrive, but throwing in a long timeout to catch any "improvements" to the protocol that you don't know about.

Your third option is to go to non-blocking sockets, which will increase your code complexity significantly. If your program needs to be dealing with multiple clients at once, or never wants to be blocking waiting for I/O, then non-blocking sockets are useful. If you only expect to be dealing with a single connection, and you don't have other things to do while waiting for that connection, you definitely want to go with blocking I/O.

Hope this solves the problem.

Cheers,
Paul

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (6)
As of 2024-03-28 23:34 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found