How to close a TCP socket? (TCPSocket#close doesn't close it)

  • Thread starter Iñaki Baz Castillo
  • Start date
I

Iñaki Baz Castillo

Hi, perhaps I miss something but when I close a TCP connection using=20
TCPSocket#close the connection remains as OS level for long seconds (minute=
s).

Be reading the doc:

IO#close

Closes ios and flushes any pending writes to the operating system. The
stream is unavailable for any further data operations; an IOError is rais=
ed
if such an attempt is made. I/O streams are automatically closed when they
are claimed by the garbage collector.

So, does it mean that the TCP connection is *really* terminated when the=20
garbage collector removes it (some seconds/minutes after calling=20
TCPSocket#close)?

Unfortunatelly it's not valid for me, I need the capability to close a TCP=
=20
connection and open a new one without mantaining two parallel connections.

Any other way to really close a TCP connection at OS level? Thanks.

=2D-=20
I=C3=B1aki Baz Castillo <[email protected]>
 
L

Lars Christensen

Hi, perhaps I miss something but when I close a TCP connection using
TCPSocket#close the connection remains as OS level for long seconds (minu= tes).

Be reading the doc:

=A0IO#close

=A0Closes ios and flushes any pending writes to the operating system. The
=A0stream is unavailable for any further data operations; an IOError is r= aised
=A0if such an attempt is made. I/O streams are automatically closed when = they
=A0are claimed by the garbage collector.

So, does it mean that the TCP connection is *really* terminated when the
garbage collector removes it (some seconds/minutes after calling
TCPSocket#close)?

The TCP connection is terminated when you call TCPSocket#close.
 
I

Iñaki Baz Castillo

El Martes, 12 de Enero de 2010, Lars Christensen escribi=F3:
=20
The TCP connection is terminated when you call TCPSocket#close.

Yes, I'm realizing of it right now. There must be some error in my code whi=
ch=20
prevents the socket from being closed. I must investigate it.

=20
Why do you need to do that? Your connection is in the TIME_WAIT state,
which is exists for good reasons. There are no parallel connections.

In my buggy script the connection remains ESTABLISHED, but as I said above =
it=20
must be my fault somewhere in the script.

However, by trying just:

require "socket"
s =3D TCPSocket.new(server, port)
s.close

After "s.close" the connection is ended totally, no TIME_WAIT status.


Thanks a lot.



=2D-=20
I=F1aki Baz Castillo <[email protected]>
 
J

Jesús Gabriel y Galán

El Martes, 12 de Enero de 2010, Lars Christensen escribi=F3:
Yes, I'm realizing of it right now. There must be some error in my code w= hich
prevents the socket from being closed. I must investigate it.



In my buggy script the connection remains ESTABLISHED, but as I said abov= e it
must be my fault somewhere in the script.

However, by trying just:

=A0require "socket"
=A0s =3D TCPSocket.new(server, port)
=A0s.close

After "s.close" the connection is ended totally, no TIME_WAIT status.

Take a look at this tutorial:

http://www.ssfnet.org/Exchange/tcp/tcpTutorialNotes.html

There's a diagram explaining all the states for a TCPSocket, and
explains the reaons for the TIME_WAIT status.

Hope this helps,

Jesus.
 
I

Iñaki Baz Castillo

El Martes, 12 de Enero de 2010, I=F1aki Baz Castillo escribi=F3:
=20
Yes, I'm realizing of it right now. There must be some error in my code
which prevents the socket from being closed. I must investigate it.

I've found the cause of my issue. My ruby script listens into a pipe and wh=
en=20
a message is received it's sent via the TCPSocket.
Also there is a thread which does @socket.gets("\r\n") to receive the=20
responses. In this way I can I can send multiple requests to the server=20
without waiting for the responses. Instead the thread doing "gets" reads th=
e=20
responses, parses a request identifier and that's all.

But in this case when calling socket.close the connection is not terminated=
=2E A=20
simplified code:

require "socket"
@socket =3D TCPSocket.new(server, port)
=20
Thread.new do
res =3D @socket.gets("\r\n")
end
=20
@socket.close
sleep 120


When "@socket.close" is called it's just closed "at Ruby level", this is, I=
=20
cannot write/read from it as I get "closed pipe" error (which makes sense).

However the TCP connection remains open at OS level (in ESTABLISHED status =
as=20
netstat shows in both the client and server).


But it's really interesting (for me) the following fact:

Without the line @socket.close netstat output shows (during the sleep 120):

tcp 0 0 192.168.1.10:51112 88.231.79.226:5062 ESTABLISHED 23814/irb
=20
But when running the script with @socket.close line then I see:

tcp 0 0 192.168.1.10:51112 88.231.79.226:5062 ESTABLISHED -

It's like if the Ruby process (irb) has detached itself from the socket (no=
=20
process pid in the netstat output for that connection), but the socket rema=
ins=20
open at OS level.

Is it the expected behavior?

Thanks.

=2D-=20
I=F1aki Baz Castillo <[email protected]>
 
I

Iñaki Baz Castillo

El Martes, 12 de Enero de 2010, Jes=FAs Gabriel y Gal=E1n escribi=F3:
=20
Take a look at this tutorial:
=20
http://www.ssfnet.org/Exchange/tcp/tcpTutorialNotes.html
=20
There's a diagram explaining all the states for a TCPSocket, and
explains the reaons for the TIME_WAIT status.

Thanks a lot, but as I've explained I don't see TIME_WAIT, my issue is=20
different (described in other mail sent right now).

Thanks.

=2D-=20
I=F1aki Baz Castillo <[email protected]>
 
B

Brian Candler

Iñaki Baz Castillo said:
But in this case when calling socket.close the connection is not
terminated. A
simplified code:

require "socket"
@socket = TCPSocket.new(server, port)

Thread.new do
res = @socket.gets("\r\n")
end

@socket.close
sleep 120

When I run this code, substituting a 'www.google.com' and port 80, I see
the socket in TIME_WAIT state if I go to another terminal.

This is with
ruby 1.8.6 (2007-09-24 patchlevel 111) [i486-linux]
built from source, running under Ubuntu Hardy.

It appears to be consistent: i.e. I can ctrl-C out of the program and
start it again, and each time I get another TIME_WAIT socket.

Whilst what you're doing is probably allowed, it's a bit ugly: one
thread is waiting to read data from a socket at the same time as another
closes it.

There is a more graceful way which might be useful. In the writing
thread you can half-close the socket (@socket.close_write). If the other
side notices this and then closes from its side, you can then finish
reading what it sends you and close the read side.

require "socket"
@socket = TCPSocket.new('smtp.example.com', 25)

Thread.new do
while res = @socket.gets("\r\n")
STDERR.puts res
end
@socket.close_read
end

@socket.close_write
sleep 120

Anyway, going back to your original code: to isolate the behaviour
you've seen, I suggest you set up a ruby server and client pair of
processes and connect between them (preferably using localhost). This
makes it completely standalone and easy to reproduce by others, and
potentially easy to fix if it is in fact a bug. Post your ruby version
and platform too.

Regards,

Brian.
 
I

Iñaki Baz Castillo

El Martes, 12 de Enero de 2010, Brian Candler escribi=C3=B3:
When I run this code, substituting a 'www.google.com' and port 80, I see
the socket in TIME_WAIT state if I go to another terminal.
=20
This is with
ruby 1.8.6 (2007-09-24 patchlevel 111) [i486-linux]
built from source, running under Ubuntu Hardy.
=20
It appears to be consistent: i.e. I can ctrl-C out of the program and
start it again, and each time I get another TIME_WAIT socket.

I really sorry, I was doing a "grep ESTABLISHED" in my netstat command...
Of course the TIME_WAIT appears after closing the connection :)
Sorry.


=20
Whilst what you're doing is probably allowed, it's a bit ugly: one
thread is waiting to read data from a socket at the same time as another
closes it.
=20
There is a more graceful way which might be useful. In the writing
thread you can half-close the socket (@socket.close_write). If the other
side notices this and then closes from its side, you can then finish
reading what it sends you and close the read side.
=20
require "socket"
@socket =3D TCPSocket.new('smtp.example.com', 25)
=20
Thread.new do
while res =3D @socket.gets("\r\n")
STDERR.puts res
end
@socket.close_read
end
=20
@socket.close_write
sleep 120

Yes, this works much better :)
Thanks a lot.


=2D-=20
I=C3=B1aki Baz Castillo <[email protected]>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,731
Messages
2,569,432
Members
44,832
Latest member
GlennSmall

Latest Threads

Top