socket.unbind or socket.unlisten? - socket.error: (48, 'Address already in use')

Mark Wooding mdw at distorted.org.uk
Tue Jan 27 18:05:24 CET 2009


Laszlo Nagy <gandalf at shopzeus.com> writes:

> I have a program that uses socket.bind() and socket.listen()
> frequently. After that program stops, it is not able to bind() again for a
> while:

This is the usual TIME-WAIT problem.  The TCP protocol requires one end
of the connection (whichever actually started the close) to keep a
record of it for a while after it closes, in order to avoid confusion
caused by old packets.

> The problem with this, is that this server program SOMETIMES need to be
> restarted very quickly.

The usual solution is to set the SO_REUSEADDR socket option before
binding.  This is safe for listening sockets.

Here's an interactive session.

        In [1]: import socket as S

        In [2]: def make_server_socket():
           ...:   sk = S.socket(S.AF_INET, S.SOCK_STREAM)
           ...:   sk.bind(('', 12345))
           ...:   sk.listen(5)
           ...:   return sk
           ...:

        In [3]: def serve_client(sk):
           ...:   (nsk, addr) = sk.accept()
           ...:   nsk.send('Hello.\n')
           ...:   nsk.close()
           ...:

        In [4]: sk = make_server_socket()

        In [5]: serve_client(sk)

(At this point, I connect to the server in another terminal.)

        In [6]: sk.close()

        In [7]: sk = make_server_socket()
        [...]
        error: (98, 'Address already in use')

And to confirm that it's TIME-WAIT that's stopping us:

[ponder ~]netstat -n | grep 12345
tcp        0      0 127.0.0.1:12345         127.0.0.1:49988         TIME_WAIT

If I change make_server_socket, then everything works fine.

        In [8]: def make_server_socket():
           ...:   sk = S.socket(S.AF_INET, S.SOCK_STREAM)
           ...:   sk.setsockopt(S.SOL_SOCKET, S.SO_REUSEADDR, 1)
           ...:   sk.bind(('', 12345))
           ...:   sk.listen(5)
           ...:   return sk
           ...:

        In [10]: sk = make_server_socket()

        In [11]: serve_client(sk)

        In [13]: sk.close()

        In [14]: sk = make_server_socket()

Done.

If you try this, note that both the old, closed socket /and/ the new one
must have SO_REUSEADDR set on them.  If you try this interactively,
you'll have to wait for the non-SO_REUSEADDR socket to leave TIME-WAIT
before you can bind.  But once you've done that, it'll work fine from
then on.

-- [mdw]



More information about the Python-list mailing list