From: "Iñaki Baz Castillo" Date: 2010-01-13T04:22:05+09:00 Subject: TCPSocket doesn't detect remote disconnection inmediatelly Hi, I'm experimenting an annoying issue when a server disconnects a TCP connection established by a Ruby client. Let me start with an example of what I consider the expected behavior: a) Using Linux "telnet" command: - First connect to google.com: ~$ telnet google.com 80 Trying 209.85.229.106... Connected to google.com. Escape character is '^]'. - Then write something ("hello\n"): hello - So I receive a 400 response: HTTP/1.0 400 Bad Request [...] - And a warning: "Connection closed by foreign host." - telnet exits with status 1 due to the remote disconnection error. b) Using Ruby 1.9.1 TCPSocket: - First connect: irb> require "socket" true irb> socket = TCPSocket.new("google.com", 80) # - Now netstat shows the connection as ESTABLISHED (ok). - Write "hello\n" into the socket: irb> socket.puts "hello" nil - I receive the same 400 response from the www server. Now netstat shows the connection as CLOSE_WAIT (OK?). - Write "hello\n" again (IMHO it should fail): irb> socket.puts "hello" nil <---- didn't raise !!! - Doing a ngrep I see that irb has sent "hello\n" over the previous TCP connection but this time it doesn't receive response from the www server. This is, irb is using a closed connection!: T 2010/01/12 20:12:04.072705 192.168.1.10:35272 -> 209.85.229.105:80 [AP] hello # - But after this new "puts" now netstat shows nothing! (no connection => OK). - Repeat again: irb> socket.puts "hello" Errno::EPIPE: Broken pipe from (irb):6:in `write' from (irb):6:in `puts' from (irb):6 from /usr/bin/irb:12:in `
' - Now it raises! Why didn't Ruby raise in the second "puts" attemp??? the server already closed the connection! Why does Ruby realize of it after a new retry? Well, this issue causes one request lost (the second one) since there is no way to know if the server accepted or dropped the request. Is it a bug? is there a way to check the socket connection before sending (loosing in fact) a request? (TCPSocket#closed? is not valid here as it just returns true in case *we* have closed a socket). Thanks a lot for any help. -- Iñaki Baz Castillo