Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to timeout a socket recv under win32?

175 views
Skip to first unread message

Horace

unread,
Jul 3, 2001, 4:34:16 AM7/3/01
to
Hi everyone,
I'm new to perl and sorry if this question has been asked before,
that's how to timeout a socket recv under win32 environmnet? I know that
under unix, I can use "alarm", but how about win32?
I saw some people suggested using "vec" and "select" to implement
the timeout, but I don't know how.
Please help and thanks in advance!

Best Regards,

Horace Tang

Michael Gilfix

unread,
Jul 3, 2001, 4:26:06 PM7/3/01
to

select and vec are the way to go. The general idiom is to open up the socket,
do polling on the socket with select and then call recv on the socket only
when there is input to be read. So assuming that you have a socket already
open, you'll probably want something like this snippet:

my ($rin, $rout) ;

# Vec sets the bit within a series of bit flags (like an integer).
# You can think of this line as setting the bit flag in a set of
# read bits so that select knows to look for data from this
# socket
vec ($rin, fileno (MY_SOCKET), 1) = 1;

# This if statement will block until input is seen at
# the file descriptor. The last argument specifies the
# timeout. You could supply a number of seconds and
# the call will return if no data is seen.
if ( select ($rout = $rin, undef, undef, undef) ) {

my $my_packet = "";
my $length_to_read = 256;
my $server = recv (SOCKET, $my_packet, $my_length_to_read, 0);
# Do more processing

}

That should give you a general idea. You can always do a:
"perldoc -f select" and "perldoc -f vec" from the command line (in unix, not
sure about win) for more info.

-- Mike

--
Michael Gilfix
Extreme Blue Group - IBM (Austin)
magi...@us.ibm.com

Horace

unread,
Jul 3, 2001, 11:02:33 PM7/3/01
to
Although I'm still not really clear what each paramter in select() represents and what
they do (excpet the timeout parameter), but by following your code, I've got the timeout
running, Thank you very much.

Horace Tang

Michael Gilfix

unread,
Jul 4, 2001, 4:59:38 PM7/4/01
to

The parameters to select (in order) are: The read vector, the write vector,
the exception vector, and the timeout. The first two are bit vectors that tell
select which file descriptors to monitor (these are set by the vec call). The
third argument specifies the file descriptors that will be watched for
exceptions. The last parameter, the timeout specifies how long select should
block before returning, provided that no input was seen.

Basically in the example below, you can think of $rin as a set of file
descriptors to monitor. When you first create $rin with my, the set is empty.
Then, using vec, you add file descriptors to the set. Finally, when you want
to poll all the file descriptors in the set, you pass them to select. The
reason that $rout is in the line is mostly for clarity and gets assigned the
file descriptor that changed while polling.

Hope that helps give you a better idea. If not, check out the C man page for
select because the perl one follows it closely (man select on any unix
machine).

-- Mike


On Tuesday 03 July 2001 22:02%, Horace wrote:

> Although I'm still not really clear what each paramter in select() represents
> and what they do (excpet the timeout parameter), but by following your code,
> I've got the timeout running, Thank you very much.
>
> Horace Tang

>> if ( select ($rout = $rin, undef, undef, undef) ) {

--

Benjamin Goldberg

unread,
Jul 14, 2001, 9:22:55 PM7/14/01
to

IO::Select is probably the easiest way to go.

use IO::Select;

my $select = IO::Select->new( \*SOCKET );

...
if( $select->can_read( $timeout ) ) {
my $sender = recv SOCKET, my $packet, 256, 0
or die "recv failed: $!";
print "Got ", length($packet), " bytes from ";
print gethostbyaddr( (sockaddr $sender)[1] ), "\n";
print unpack("H*",$packet), "\n";
}

--
The longer a man is wrong, the surer he is that he's right.

Bart Lateur

unread,
Jul 15, 2001, 6:13:04 AM7/15/01
to
Benjamin Goldberg wrote:

>IO::Select is probably the easiest way to go.

>if( $select->can_read( $timeout ) ) {


> my $sender = recv SOCKET, my $packet, 256, 0
> or die "recv failed: $!";

So you mean recv().

So, next question: what's the difference between sysread() and recv()?
What are the similarities? Why are both available in perl?

--
Bart.

nob...@mail.com

unread,
Jul 15, 2001, 7:42:18 AM7/15/01
to
Bart Lateur <bart....@skynet.be> writes:

> Benjamin Goldberg wrote:
>
> >IO::Select is probably the easiest way to go.
>
> >if( $select->can_read( $timeout ) ) {
> > my $sender = recv SOCKET, my $packet, 256, 0
> > or die "recv failed: $!";
>
> So you mean recv().
>
> So, next question: what's the difference between sysread() and recv()?

recv() can give you more information when reading from a socket. For
example on UDP it tells you where the datagram came from.

> What are the similarities?

The simplest use of recv() is equivalent a sysread().

> Why are both available in perl?

IIRC recv() can't be used on non-socket file handles. (This is
probably not true of all OS).

--
\\ ( )
. _\\__[oo
.__/ \\ /\@
. l___\\
# ll l\\
###LL LL\\

Benjamin Goldberg

unread,
Jul 16, 2001, 12:08:19 AM7/16/01
to
Bart Lateur wrote:
>
> Benjamin Goldberg wrote:
>
> >IO::Select is probably the easiest way to go.
>
> >if( $select->can_read( $timeout ) ) {
> > my $sender = recv SOCKET, my $packet, 256, 0
> > or die "recv failed: $!";
>
> So you mean recv().

Umm, what do you mean by that comment?

Samuel Kilchenmann

unread,
Jul 16, 2001, 4:17:07 AM7/16/01
to
"Bart Lateur" <bart....@skynet.be> schrieb im Newsbeitrag
news:k4r2ltchhp5sk0dd8...@4ax.com...

> Benjamin Goldberg wrote:
>
> >IO::Select is probably the easiest way to go.
>
> >if( $select->can_read( $timeout ) ) {
> > my $sender = recv SOCKET, my $packet, 256, 0
> > or die "recv failed: $!";
>
> So you mean recv().
>
> So, next question: what's the difference between sysread() and recv()?

Not so long ago it was not uncommon that you had to install a TCP/IP
implementation as an add-on to the OS (e.g. on SysV systems before SysVR4).
In this case there are different systemcalls to read from a filehandle and
to read from a socket. recv() is the systemcall to read from sockets on such
systems. It was always a feature of very high-level languages to hide such
differences from the programmer. This is still true today: it might very
well be that sysread() on sockets is implemented in terms of calls to recv()
on some systems (e.g. Win32 systems).

> What are the similarities? Why are both available in perl?

The most prominent difference between read() and recv() is that recv() takes
an additional flags argument. Most often the recv() flags available are only
MSG_OOB and MSG_PEEK, but some TCP/IP implementations offer more flags (e.g.
to make a single recv() non-blocking (MSG_DONTWAIT) or to ensure that recv()
only returns after it received the requested number of bytes (MSG_WAITALL),
etc.)

The main reason to have both functions in Perl is a different one: Perls
recv() is implemented in terms of recvfrom() and this one can be used to
return information about the sender of a datagram received on an UDP socket.


Bart Lateur

unread,
Jul 18, 2001, 8:25:45 AM7/18/01
to
Benjamin Goldberg wrote:

>> So you mean recv().
>
>Umm, what do you mean by that comment?

Oops, I have ben mixing threads. I cconfused this with another current
thread, where the OP asked how you can know how many bytes there are
currently available for reading.

It all boils down to this: how do you receive all the data that the
other side is sending to you, without waiting for more that won't come?
How do you know that, for the moment, the transmission is complete?

<S>, read, sysread, recv are similar yet different. I guess that only
read() is not usable. select() or IO::Select can tell you that something
is available, but not how much. I have the feeling that there isn't a
real generic solution, that the sender somehow HAS to indicate how long
the transmission will be. Otherwise, the receiver can stop receiving too
soon, or wait for something that won't come.

--
Bart.

Anno Siegel

unread,
Jul 18, 2001, 10:33:37 AM7/18/01
to
According to Bart Lateur <bart....@skynet.be>:

There must be *some* protocol sender and receiver agree upon, but
not necessarily pre-announcement of length. If the sender always
sends complete lines, even read() is usable, because a transmission
isn't finished unless a line is finished.

Or am I solving a different problem?

Anno

Haber Schabernackel

unread,
Jul 18, 2001, 2:20:06 PM7/18/01
to
On Wed, 18 Jul 2001 12:25:45 GMT, Bart Lateur <bart....@skynet.be> wrote:
> Benjamin Goldberg wrote:
>
> >> So you mean recv().
> >
> >Umm, what do you mean by that comment?
>
> Oops, I have ben mixing threads. I cconfused this with another current
> thread, where the OP asked how you can know how many bytes there are
> currently available for reading.
>
> It all boils down to this: how do you receive all the data that the
> other side is sending to you, without waiting for more that won't come?
> How do you know that, for the moment, the transmission is complete?

Can't you just receive something from a socket with <HANDLE> ?
I'm not sure if this solution is bulletproof, but works for me:
(althougt it sometimes hangs, not sure where, any comments?
i've tried $sock->timeout(10) but it doesnt seem to work)

use IO::Socket;
my $host='www.perl.com';
my $sock=IO::Socket::INET->new("$host:80");
$sock->autoflush(1);
my $EOL="\015\012";
my($http,$html);
print $sock "GET / HTTP/1.1${EOL}Host: $host$EOL$EOL";
1../^[\s$EOL]*$/ ? ($http.=$_) : ($html.=$_) while <$sock>;
close($sock);

$Bill Luebkert

unread,
Jul 18, 2001, 6:46:09 PM7/18/01
to

On Win32, the way to handle reads is:

1) Don't read until IO::Select can_read tells you there is data available.

2) Read until you get less data than you asked for (or an error/eof) condition.

3) After 2) go back to 1).

--
,-/- __ _ _ $Bill Luebkert ICQ=14439852
(_/ / ) // // DBE Collectibles Mailto:d...@todbe.com
/ ) /--< o // // http://dbecoll.webjump.com/ (Free site for Perl)
-/-' /___/_<_</_</_ Castle of Medieval Myth & Magic http://www.todbe.com/

Benjamin Goldberg

unread,
Jul 23, 2001, 1:45:21 AM7/23/01
to
Bart Lateur wrote:
>
> Benjamin Goldberg wrote:
>
> >> So you mean recv().
> >
> >Umm, what do you mean by that comment?
>
> Oops, I have ben mixing threads. I cconfused this with another current
> thread, where the OP asked how you can know how many bytes there are
> currently available for reading.
>
> It all boils down to this: how do you receive all the data that the
> other side is sending to you, without waiting for more that won't
> come?
> How do you know that, for the moment, the transmission is complete?

Either you use fixed-length packets, or use a delimiter (like CRLF).

> <S>, read, sysread, recv are similar yet different. I guess that only
> read() is not usable. select() or IO::Select can tell you that
> something is available, but not how much. I have the feeling that
> there isn't a real generic solution, that the sender somehow HAS to
> indicate how long the transmission will be. Otherwise, the receiver
> can stop receiving too soon, or wait for something that won't come.

If you're dealing with a tcp stream, not a udp socket, then you probably
don't need/want to be using recv. <>, read, and sysread are all useful.

If you know that data is sent in packets of a fixed size, and you aren't
afraid of DOS attacks, then you can simply use select or IO::Select
to get to a point when you know that there is *some* data on the stream,
and then *assume* [here's where a DOS attack could come in] that one
whole packet will then be available, and do a blocking read (either
with read(), or with $/ = \recordlength and <>) for that many bytes.

my $sel = IO::Select->new($socket);
while( $sel->can_read(0) ) {
my $packet;
my $got = read( $socket, $packet, 40 );
$got == 40 or die "read: $!";
push @packets, $packet;
}

or:
my $sel = IO::Select->new($socket);
while( $sel->can_read(0) ) {
local $/ = \40;
my $packet = <$socket>;
length($packet) == 40 or die "read: $!";
push @packets, $packet;
}

Similarly, if you know that data will be sent in complete packets with
some particular delimiter, you can block until *something* is there,
and then read with <> (and $/ = delimiter) until you get the entire
packet.

my $sel = IO::Select->new($socket);
while( $sel->can_read(0) ) {
local $/ = CRLF;
chomp( my $packet = <$socket> ) or die "read: $!";
push @packets, $packet;
}

With either of these, the only problem that can occur if the other end
decides to stop/pause right in the middle of a packet; if you are
willing to ignore such problems, then you're all set.

Otherwise, read on.

If you want to *try* to use normal buffered io (read or <>), but set a
timeout... read the faq. You would probably use %SIG, eval BLOCK, and
alarm in combination to abort the read if it takes too long to complete.
Since the buffers for the file will then be in some undeterminable
state, and some data may even have been lost, all you can now do is
print out a message and close the stream (and maybe abort your program,
depending on the application).

Elsewise, use unbuffered io, using the sysread function.

The sysread function reads without requiring that a complete record
(packet) is there before returning... it does block until *some* data
has been gotten, but once it has that, it will return with what it has.

my $sel = IO::Select->new($socket);
while( $sel->can_read(0) ) {
my $gotabit;
sysread( $socket, $gotabit, 1<<10 )
or die "sysread: $!";
$buffer .= $gotabit;
}

This will append to $buffer as many bytes as can be read without
blocking. It will read *up to* 1024 bytes, but won't try to wait until
there are that many available.

Normally, one would have a hash mapping sockets to 'buffer' objects of
some sort, do select on all the sockets, then for each 'buffer' objects
which has a readable socket, have it read in all it can without
blocking, then, if enough has been read to do something, substr that
text off of the front of the buffer and process it:

while( length( $self->{buffer} ) >= $len ) {
$to_process = substr($self->{buffer}, 0, $len, "");
$self->process_input($to_process);
}

--
I need more taglines. This one is getting old.

0 new messages