Hi, How to set socket option SO_RCVTIMEO in Windows XP? The C version use somekind struct. Regards, -- Zakaria z4k4ri4@gmail.com Yahoo!: z4k4ri4
on 2006-11-30 09:51

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
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?
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?
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
on 2008-11-14 00:51

How about something like: s = Socket.new(...) s.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, ...) s.connect(...) --wpd
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
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 }
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
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 > }