I'm reading lines of input on a TCP socket, similar to this:
class Bla
def getcmd
@sock.gets unless @sock.closed?
end
def start
srv = TCPServer.new(5000)
@sock = srv.accept
while ! @sock.closed?
ans = getcmd
end
end
end
If the endpoint terminates the connection while getline() is running then gets() hangs.
How can I work around this? Is it necessary to do non-blocking or timed I/O?
I simply pgrep "ruby" to find the pid, and kill -9 the pid and restart.
I recommend using readpartial to read from your socket and also catching peer resets:
This code borrows heavily from some nice IBM code by M. Tim Jones. Note that @server_socket is initialized by:
@sockets is just an array of sockets.
The IO#closed? returns true when both reader and writer are closed. In your case, the @sock.gets returns nil, and then you call the getcmd again, and this runs in a never ending loop. You can either use select, or close the socket when gets returns nil.
You can use select to see whether you can safely gets from the socket, see following implementation of a TCPServer using this technique.
And here a client that tries to break the server:
If you believe the rdoc for ruby sockets, they don't implement
gets
. This leads me to believe gets is being provided by a higher level of abstraction (maybe the IO libraries?) and probably isn't aware of socket-specific things like 'connection closed.'Try using
recvfrom
instead ofgets