2

I've created a server socket on port 6379, like this:

>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> s.bind(('localhost', 6379))
>>> s.listen(1)

lsof shows it is in an LISTEN state (I've removed some of lsof's columns for readability):

Python    13800 IPv4 TCP localhost:6379 (LISTEN)

... now I'll make a client socket and connect ...

>>> s.connect(('localhost', 6379))

... lsof shows ESTABLISHED ...

Python    13800 IPv4 TCP localhost:6379 (LISTEN)
Python    13838 IPv4 TCP localhost:63075->localhost:6379 (ESTABLISHED)

Then I start my redis server. Here's everything that seems to be using 6379, courtesy of lsof:

Python    13800 IPv4 TCP localhost:6379 (LISTEN)
Python    13838 IPv4 TCP localhost:63075->localhost:6379 (ESTABLISHED)
redis-ser 13855 IPv6 TCP *:6379 (LISTEN)
redis-ser 13855 IPv4 TCP *:6379 (LISTEN)

I'll add something to redis to start up another connection:

>>> r = redis.StrictRedis('localhost', 6379)
>>> r.set('foo', 'bar')

... which I can see in lsof...

Python    13800 IPv4 TCP localhost:6379 (LISTEN)
Python    13838 IPv4 TCP localhost:63075->localhost:6379 (ESTABLISHED)
redis-ser 13855 IPv6 TCP *:6379 (LISTEN)
redis-ser 13855 IPv4 TCP *:6379 (LISTEN)
redis-ser 13855 IPv6 TCP localhost:6379->localhost:63084 (ESTABLISHED)

So my question is... if I do this in the reverse order, e.g. run "redis-server" first, then try to make a socket bound to port 6379, I get an "address already in use" error.

Why is redis allowed to use the port when Python already is, but not vice versa?

For example...

redis --port 1234

... that works fine, but if I try to make a Python socket while it's running:

>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> s.bind(('localhost', 1234))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 228, in meth
    return getattr(self._sock,name)(*args)
socket.error: [Errno 48] Address already in use
almaghest
  • 103
  • 2
  • 6

1 Answers1

1

Two possibilities:

  1. You'll notice that redis is bound to "*" while python is bound to localhost. So when redis is launched second, it is still allowed to bind because it is listening more generally: there could be an incoming connection not from localhost, and redis could handle that instead of python. But when redis listens first, there are now no addresses which could be handled by a different program, so it is not possible to open on the same port. You can read more about the UNIX program route for details.

  2. There is an SO_REUSEPORT option which allows multiple servers to listen on the same port, and incoming connections are sent to a random server. Can two applications listen to the same port? redis may be using this to support load-balancing. I would expect its listen to be rejected if the python program does not specify this flag however.

Community
  • 1
  • 1
dwks
  • 602
  • 5
  • 10