Reputation: 893
I have a very simple socket app:
# Server
server = TCPServer.new(2000)
loop do
client = server.accept
sleep 10
end
# Client
s = TCPSocket.new('localhost', 2000)
th1 = Thread.new do
begin
Kernel.select([s], nil, [s], nil)
puts 'Select returned'
rescue => e
puts "Select raised #{e}"
end
end
th2 = Thread.new do
sleep 0.5
s.close
end
[th1, th2].map(&:join)
Now, what I want to happen is, if while the client is hanging waiting for the server to respond, the client's socket is closed by a different thread, the Kernel#select
call should exit immediately and raise an error. This is what happens on MacOs, however on Linux, the call to select
hangs indefinitely (or until the timeout is hit).
Any help would be appreciated!
Upvotes: 0
Views: 85
Reputation: 180161
Is there any way to get around this?
Instead of trying to interrupt the waiting thread by closing the local socket, include the read end of a pipe among the IO objects it is select
ing on. Then another thread can interrupt the select
ion by writing to or closing the write end of the pipe. That has the added advantage that it allows the client to distinguish between a local termination request and a remote disconnection.
Something along these lines, for example:
rd, wr = IO.pipe
# ...
#
# thread 1
#
sock = # ...
# ...
ready = Kernel.select([sock, rd], nil, [sock, rd], timeout)
if ready.nil?
# handle timeout ...
elsif ready.flatten.include? rd
# handle local termination request ...
else
# handle socket ...
end
#
# thread 2
#
# Interrupt thread 1
wr.close
Upvotes: 1