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

L

Laszlo Nagy

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:

File "/home/gandalf/Python/Lib/orb/accesspoints/srvtcp.py", line 27, in
__init__
self.serversocket.bind((self.listen_address,self.port))
File "<string>", line 1, in bind
socket.error: (48, 'Address already in use')


The problem with this, is that this server program SOMETIMES need to be
restarted very quickly. I tried to find the solution in the socket
module. But there is no "socket.unbind" or "socket.unlisten". How can I
tell the OS that I do not want to listen on that address anymore, so
other programs can bind on it immediatelly?

(Yes I know that I can use setsockopt to allow listening multiple
sockets on the same address, but this is NOT what I need...)

Thanks,

Laszlo
 
M

Mark Wooding

Laszlo Nagy said:
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]
 

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