Skip to content

Instantly share code, notes, and snippets.

@gabrielfalcao
Created October 31, 2015 18:30
Show Gist options
  • Star 22 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save gabrielfalcao/20e567e188f588b65ba2 to your computer and use it in GitHub Desktop.
Save gabrielfalcao/20e567e188f588b65ba2 to your computer and use it in GitHub Desktop.
Getting a random free tcp port in python using sockets
# Getting a random free tcp port in python using sockets
def get_free_tcp_port():
tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp.bind(('', 0))
addr, port = tcp.getsockname()
tcp.close()
return port
def get_free_tcp_address():
tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp.bind(('', 0))
host, port = tcp.getsockname()
tcp.close()
return 'tcp://{host}:{port}'.format(**locals())
@corydodt
Copy link

This has a race condition, since another process may grab that port after tcp.close(). This might be ok, if you simply catch the exception and try again, although it strikes me as possibly insecure to do so.

@hrvolapeter
Copy link

Might be helpful for others: the port from get_free_tcp_port cannot be used immediately after function returns. port will be in state TIME_WAIT for approx 30-60s after closing and cannot be reused before that without explicitly passing SO_REUSEPORT

@couling
Copy link

couling commented Feb 17, 2022

This is useful for showing that

  • 0 as the socket number lets the OS select the port
  • getsocketname() will return the address.

But beyond that you should never do it this way. As @corydodt points out there's a race condition. Rather like creating a temporary file you should both allocate the address (including port) and create the socket in one atomic step:

def open_ephemeral_socket():
    tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    tcp.bind(('', 0))
    return tcp.getsockname(), address

In this case you would then use the returned socket not try to open a new one on the same port.

Note that the atomic nature of this code is backed up by the operating system. It allocates the port and creates the socket in one go so there is no chance of any race condition.

@s3rgeym
Copy link

s3rgeym commented Mar 4, 2024

more modern and pythonic:

import socket
from contextlib import closing


def get_local_ip() -> str:
    with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
        s.connect(("8.8.8.8", 53))
        return s.getsockname()[0]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment