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

Discussion in 'Ruby' started by Iñaki Baz Castillo, Jan 12, 2010.

  1. 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 <>
    Iñaki Baz Castillo, Jan 12, 2010
    #1
    1. Advertising

  2. On Tue, Jan 12, 2010 at 11:43 AM, I=F1aki Baz Castillo <> wrot=
    e:
    > 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.

    > Unfortunatelly it's not valid for me, I need the capability to close a TC=

    P
    > connection and open a new one without mantaining two parallel connections=
    Lars Christensen, Jan 12, 2010
    #2
    1. Advertising

  3. El Martes, 12 de Enero de 2010, Lars Christensen escribi=F3:
    > On Tue, Jan 12, 2010 at 11:43 AM, I=F1aki Baz Castillo <> wr=

    ote:
    > > Hi, perhaps I miss something but when I close a TCP connection using
    > > TCPSocket#close the connection remains as OS level for long seconds
    > > (minutes).
    > >
    > > 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
    > > raised 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
    > > garbage collector removes it (some seconds/minutes after calling
    > > TCPSocket#close)?

    >=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.


    > > Unfortunatelly it's not valid for me, I need the capability to close a
    > > TCP connection and open a new one without mantaining two parallel
    > > connections.
    > >
    > > Any other way to really close a TCP connection at OS level? Thanks.

    >=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 <>
    Iñaki Baz Castillo, Jan 12, 2010
    #3
  4. On Tue, Jan 12, 2010 at 12:26 PM, I=F1aki Baz Castillo <> wrot=
    e:
    > El Martes, 12 de Enero de 2010, Lars Christensen escribi=F3:
    >> On Tue, Jan 12, 2010 at 11:43 AM, I=F1aki Baz Castillo <> w=

    rote:
    >> > Hi, perhaps I miss something but when I close a TCP connection using
    >> > TCPSocket#close the connection remains as OS level for long seconds
    >> > (minutes).
    >> >
    >> > 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 i=

    s
    >> > raised if such an attempt is made. I/O streams are automatically close=

    d
    >> > when they are claimed by the garbage collector.
    >> >
    >> > So, does it mean that the TCP connection is *really* terminated when t=

    he
    >> > garbage collector removes it (some seconds/minutes after calling
    >> > TCPSocket#close)?

    >>
    >> 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 w=

    hich
    > prevents the socket from being closed. I must investigate it.
    >
    >
    >> > Unfortunatelly it's not valid for me, I need the capability to close a
    >> > TCP connection and open a new one without mantaining two parallel
    >> > connections.
    >> >
    >> > Any other way to really close a TCP connection at OS level? Thanks.

    >>
    >> 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 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.
    Jesús Gabriel y Galán, Jan 12, 2010
    #4
  5. El Martes, 12 de Enero de 2010, I=F1aki Baz Castillo escribi=F3:

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

    >=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 <>
    Iñaki Baz Castillo, Jan 12, 2010
    #5
  6. El Martes, 12 de Enero de 2010, Jes=FAs Gabriel y Gal=E1n escribi=F3:

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

    >=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 <>
    Iñaki Baz Castillo, Jan 12, 2010
    #6
  7. Iñaki Baz Castillo wrote:
    > 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.
    --
    Posted via http://www.ruby-forum.com/.
    Brian Candler, Jan 12, 2010
    #7
  8. 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 <>
    Iñaki Baz Castillo, Jan 12, 2010
    #8
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Tiger
    Replies:
    5
    Views:
    951
    Dave Thompson
    May 1, 2006
  2. Replies:
    7
    Views:
    866
  3. Guest
    Replies:
    2
    Views:
    93
    Robert Klemme
    Jan 9, 2009
  4. Iñaki Baz Castillo
    Replies:
    7
    Views:
    529
    Iñaki Baz Castillo
    Jan 12, 2010
  5. Alex Young
    Replies:
    7
    Views:
    113
    Robert Klemme
    Feb 13, 2011
Loading...

Share This Page