I
Iñaki Baz Castillo
Hi, I'm experimenting an annoying issue when a server disconnects a TCP=20
connection established by a Ruby client.
Let me start with an example of what I consider the expected behavior:
a) Using Linux "telnet" command:
=2D First connect to google.com:
~$ telnet google.com 80 =
=20
Trying 209.85.229.106... =
=20
Connected to google.com. =
=20
Escape character is '^]'.
=2D Then write something ("hello\n"):
hello
=2D So I receive a 400 response:
HTTP/1.0 400 Bad Request
[...]
=2D And a warning:
"Connection closed by foreign host."
=2D telnet exits with status 1 due to the remote disconnection error.
b) Using Ruby 1.9.1 TCPSocket:
=2D First connect:
irb> require "socket"
true
irb> socket =3D TCPSocket.new("google.com", 80)
#<TCPSocket:0x00000001010288>
=2D Now netstat shows the connection as ESTABLISHED (ok).
=2D Write "hello\n" into the socket:
irb> socket.puts "hello"
nil
=2D I receive the same 400 response from the www server. Now netstat shows =
the=20
connection as CLOSE_WAIT (OK?).
=2D Write "hello\n" again (IMHO it should fail):
irb> socket.puts "hello"
nil <---- didn't raise !!!
=2D Doing a ngrep I see that irb has sent "hello\n" over the previous TCP=20
connection but this time it doesn't receive response from the www server. T=
his=20
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
#
=2D But after this new "puts" now netstat shows nothing! (no connection =3D=
=2D 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 `<main>'
=2D Now it raises!
Why didn't Ruby raise in the second "puts" attemp??? the server already clo=
sed=20
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=
=20
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=20
(loosing in fact) a request? (TCPSocket#closed? is not valid here as it jus=
t=20
returns true in case *we* have closed a socket).
Thanks a lot for any help.
=2D-=20
I=C3=B1aki Baz Castillo <[email protected]>
connection established by a Ruby client.
Let me start with an example of what I consider the expected behavior:
a) Using Linux "telnet" command:
=2D First connect to google.com:
~$ telnet google.com 80 =
=20
Trying 209.85.229.106... =
=20
Connected to google.com. =
=20
Escape character is '^]'.
=2D Then write something ("hello\n"):
hello
=2D So I receive a 400 response:
HTTP/1.0 400 Bad Request
[...]
=2D And a warning:
"Connection closed by foreign host."
=2D telnet exits with status 1 due to the remote disconnection error.
b) Using Ruby 1.9.1 TCPSocket:
=2D First connect:
irb> require "socket"
true
irb> socket =3D TCPSocket.new("google.com", 80)
#<TCPSocket:0x00000001010288>
=2D Now netstat shows the connection as ESTABLISHED (ok).
=2D Write "hello\n" into the socket:
irb> socket.puts "hello"
nil
=2D I receive the same 400 response from the www server. Now netstat shows =
the=20
connection as CLOSE_WAIT (OK?).
=2D Write "hello\n" again (IMHO it should fail):
irb> socket.puts "hello"
nil <---- didn't raise !!!
=2D Doing a ngrep I see that irb has sent "hello\n" over the previous TCP=20
connection but this time it doesn't receive response from the www server. T=
his=20
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
#
=2D But after this new "puts" now netstat shows nothing! (no connection =3D=
OK).
=2D 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 `<main>'
=2D Now it raises!
Why didn't Ruby raise in the second "puts" attemp??? the server already clo=
sed=20
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=
=20
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=20
(loosing in fact) a request? (TCPSocket#closed? is not valid here as it jus=
t=20
returns true in case *we* have closed a socket).
Thanks a lot for any help.
=2D-=20
I=C3=B1aki Baz Castillo <[email protected]>