получить открытый порт TCP в Python - PullRequest
25 голосов
/ 15 мая 2010

Я хочу получить любой произвольно открытый TCP-порт на localhost в Python. Какой самый простой способ?

Ответы [ 5 ]

44 голосов
/ 15 мая 2010

Мое текущее решение:

def get_open_port():
        import socket
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.bind(("",0))
        s.listen(1)
        port = s.getsockname()[1]
        s.close()
        return port

Не очень хорошо и тоже не на 100% правильно, но пока работает.

7 голосов
/ 31 марта 2016

Свободный порт можно найти, привязав сокет к порту, выбранному операционной системой. После того, как операционная система выберет порт, сокет может быть удален. Однако это решение не является устойчивым к условиям гонки - за короткое время между получением номера свободного порта и использованием этого порта другой процесс может использовать этот порт.

def find_free_port():
    s = socket.socket()
    s.bind(('', 0))            # Bind to a free port provided by the host.
    return s.getsockname()[1]  # Return the port number assigned.
3 голосов
/ 15 мая 2010

Я фактически использую следующее в одной из моих программ:

port = random.randint(10000,60000)

Конечно, это даже более склонно к коллизиям, чем ваш код. Но у меня никогда не было проблем с этим. Дело в том, что в любой момент времени большинство из этих портов с высокими номерами не используются, и если вы просто выберете один случайным образом, конфликт с другим процессом маловероятен. Если вы делаете что-то наподобие решения, которое вы опубликовали в своем ответе (открывая сокет и захватывая номер его порта), почти наверняка порт не будет конфликтовать. Поэтому, если это то, что вы будете использовать только для себя (в отличие от того, что вы собираетесь опубликовать для публики), подумайте, стоит ли придумывать действительно пуленепробиваемое решение. Скорее всего, это никогда не изменится.

По мотивам комментария Марсело Кантоса по вашему вопросу я добавлю, что стандартное решение в подобных случаях заключается в том, чтобы процесс, использующий порт, привязывался к нему, а затем передавал эту информацию любой другой программе, которая в этом нуждается , Как правило, это будет что-то вроде записи временного файла, содержащего номер порта, в какое-то стандартное место в файловой системе. Поскольку процесс, с которым вы работаете, этого не делает, в каком-то смысле любое решение, которое вы придумали, будет чем-то вроде хака. Но опять же, если это только для вашего собственного использования, это, вероятно, хорошо.

1 голос
/ 09 сентября 2015

Эфемерные порты в основном находятся в диапазоне 49152 - 65535. если вы хотите проверить порты в большем диапазоне, просто измените значения в randint.

import pustil
from random import randint
def getfreeport():
    port = randint(49152,65535)
    portsinuse=[]
    while True:
        conns = pstuil.net_connections()
        for conn in conns:
            portsinuse.append(con.laddr[1])
        if port in portsinuse:
            port = randint(49152,65535)
        else:
            break
    return port
1 голос
/ 01 марта 2014

Это моя версия, однако она не очень случайна, если указать диапазон портов. Это также пострадает от условий гонки, но это лучший способ, который я знаю, если вам нужно знать порт заранее.

import socket
import errno
import contextlib

reserved_ports = set()

def get_open_port(lowest_port = 0, highest_port = None, bind_address = '', *socket_args, **socket_kwargs):
    if highest_port is None:
        highest_port = lowest_port + 100
    while lowest_port < highest_port:
        if lowest_port not in reserved_ports:
            try:
                with contextlib.closing(socket.socket(*socket_args, **socket_kwargs)) as my_socket:
                    my_socket.bind((bind_address, lowest_port))
                    this_port = my_socket.getsockname()[1]
                    reserved_ports.add(this_port)
                    return this_port
            except socket.error as error:
                if not error.errno == errno.EADDRINUSE:
                    raise
                assert not lowest_port == 0
                reserved_ports.add(lowest_port)
        lowest_port += 1
    raise Exception('Could not find open port')
...