Forum: Ruby How to set socket option SO_RCVTIMEO

1e5fda1286b576396465d145426e701b?d=identicon&s=25 Zakaria (Guest)
on 2006-11-30 09:51
(Received via mailing list)
Hi,

How to set socket option SO_RCVTIMEO in Windows XP?
The C version use somekind struct.

Regards,


-- Zakaria
   z4k4ri4@gmail.com             Yahoo!: z4k4ri4
2f9e362492d2f7a704a5bb1212fff182?d=identicon&s=25 Kem Mason (bulbous)
on 2008-11-13 19:11
Did you ever find out how to do this?  I am looking around, haven't
found any documentation

Zakaria wrote:
> Hi,
>
> How to set socket option SO_RCVTIMEO in Windows XP?
> The C version use somekind struct.
>
> Regards,
>
>
> -- Zakaria
>    z4k4ri4@gmail.com             Yahoo!: z4k4ri4
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2008-11-13 22:23
Zakaria wrote:
> How to set socket option SO_RCVTIMEO in Windows XP?
> The C version use somekind struct.

First, read the option:

irb(main):001:0> require 'socket'
=> true
irb(main):002:0> s = TCPServer.new(1234)
=> #<TCPServer:0xb7d246d4>
irb(main):003:0> s.getsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO)
=> "\000\000\000\000\000\000\000\000"

So if it's a struct timeval, that's a 32-bit tv_sec followed by a 32-bit
tv_usec. Not clear about the byte order, though, since it's all zero
here.

So let's try native byte ordering, to set a timeout of 1.5 seconds (1
second + 500,000 microseconds):

irb(main):008:0> n = [1, 500_000].pack("I_2")
=> "\001\000\000\000 \241\a\000"
irb(main):009:0> s.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, n
)
=> 0
irb(main):010:0> s.accept
Errno::EAGAIN: Resource temporarily unavailable
  from (irb):10:in `accept'
  from (irb):10
  from :0

Yep, there was a pause of 1.5 seconds before the exception was raised.

Look OK?
2f9e362492d2f7a704a5bb1212fff182?d=identicon&s=25 Kem Mason (bulbous)
on 2008-11-13 22:39
I tried something like that, and it never timed out -- so after your
post, I tried the following (the server I'm connecting to reads a CRLF
terminated string, and returns a response after X seconds (150 in this
case))

sock = TCPSocket.new('foodlinux', 3232)
=> #<TCPSocket:0x2be080>
opt = [1, 1].pack("I_2")
=> "\001\000\000\000\001\000\000\000"
sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, opt)
=> 0
sock.write("150\r\n")
=> 5
puts "read: #{sock.gets}"
....

it never times out -- seems like it should return after 1.000001 seconds
regardless of the byte ordering.

What am I missing here?





Brian Candler wrote:
> Zakaria wrote:
>> How to set socket option SO_RCVTIMEO in Windows XP?
>> The C version use somekind struct.
>
> First, read the option:
>
> irb(main):001:0> require 'socket'
> => true
> irb(main):002:0> s = TCPServer.new(1234)
> => #<TCPServer:0xb7d246d4>
> irb(main):003:0> s.getsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO)
> => "\000\000\000\000\000\000\000\000"
>
> So if it's a struct timeval, that's a 32-bit tv_sec followed by a 32-bit
> tv_usec. Not clear about the byte order, though, since it's all zero
> here.
>
> So let's try native byte ordering, to set a timeout of 1.5 seconds (1
> second + 500,000 microseconds):
>
> irb(main):008:0> n = [1, 500_000].pack("I_2")
> => "\001\000\000\000 \241\a\000"
> irb(main):009:0> s.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, n
> )
> => 0
> irb(main):010:0> s.accept
> Errno::EAGAIN: Resource temporarily unavailable
>   from (irb):10:in `accept'
>   from (irb):10
>   from :0
>
> Yep, there was a pause of 1.5 seconds before the exception was raised.
>
> Look OK?
2f9e362492d2f7a704a5bb1212fff182?d=identicon&s=25 Kem Mason (bulbous)
on 2008-11-14 00:32
It appears that I am supposed to call setsockopt before connecting --
which would explain why your example (which calls setsockopt before
calling accept()) works, and mine, where it is client side, does not.  I
have yet to figure out how to create a client socket that I can call
setsockopt on without connecting right away.

I'll post any update
Ed437e52d8d6720308720e7e678f3e6d?d=identicon&s=25 Patrick Doyle (Guest)
on 2008-11-14 00:51
(Received via mailing list)
How about something like:

s = Socket.new(...)
s.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, ...)
s.connect(...)

--wpd
2f9e362492d2f7a704a5bb1212fff182?d=identicon&s=25 Kem Mason (bulbous)
on 2008-11-14 00:53
hehe yeh I just realized I could use a regular Socket instead of a TCP
Socket -- it doesn't appear to be the only problem though.  here's my
latest code (which still doesn't timeout properly)


require 'socket'

opt = [1, 500_000].pack("I_2")

sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
sockaddr = Socket.pack_sockaddr_in(3232, '192.168.1.10')

sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, opt)
puts "sockopt = #{sock.getsockopt(Socket::SOL_SOCKET,
Socket::SO_RCVTIMEO).inspect}"

sock.connect(sockaddr)

#this tells the server at 192.168.1.10:3232 to wait 10 seconds before
responding, so we should get a timeout on our socket
sock.write("10\r\n")

start_time = Time.now
result = sock.gets
time = Time.now - start_time

puts "read: #{sock.gets} after: #{time} seconds"
#no timeout occured, this read returns after 10 seconds




Patrick Doyle wrote:
> How about something like:
>
> s = Socket.new(...)
> s.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, ...)
> s.connect(...)
>
> --wpd
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2008-11-14 09:07
Kem Mason wrote:
> hehe yeh I just realized I could use a regular Socket instead of a TCP
> Socket -- it doesn't appear to be the only problem though.  here's my
> latest code (which still doesn't timeout properly)

Well, probably you shouldn't be using setsockopt for this at all. Note
that setting SO_RCVTIMEO just raises an EAGAIN on timeout; I'd expect
that gets would trap that and retry.

Why not simply:

require 'timeout'
result = nil
timeout(1.5) {
  result = sock.gets
}
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2008-11-14 09:10
Also, if you're not concerned about the possibility of transmission
stopping part way through a response, you can do

if select([sock],nil,nil,1.5)
  result = sock.gets
else
  puts "I timed out!"
end
2f9e362492d2f7a704a5bb1212fff182?d=identicon&s=25 Kem Mason (bulbous)
on 2008-11-14 17:25
The problem with using timeout is that it is unsafe: (see
http://tinyurl.com/5fngha )
I have actually encountered a problem using timeout where my thread hung
forever (10 times in production over the last couple months) -- so this
is why I am starting to do something else.

You're right that gets silently ignores the exception -- turns out that
was the main problem -- if I use sock.recvfrom, I get the exception as I
want -- then I just have to handle the case where I get only part of the
response (and still have time left).

All is working now when using the code at: http://pastie.org/314914

thanks much for your help all


Brian Candler wrote:
> Kem Mason wrote:
>> hehe yeh I just realized I could use a regular Socket instead of a TCP
>> Socket -- it doesn't appear to be the only problem though.  here's my
>> latest code (which still doesn't timeout properly)
>
> Well, probably you shouldn't be using setsockopt for this at all. Note
> that setting SO_RCVTIMEO just raises an EAGAIN on timeout; I'd expect
> that gets would trap that and retry.
>
> Why not simply:
>
> require 'timeout'
> result = nil
> timeout(1.5) {
>   result = sock.gets
> }
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.