Вопрос

Я хочу получить любой случайный открытый порт TCP на Localhost в Python. Что проще всего?

Это было полезно?

Решение

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

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% правильно, но сейчас работает.

Другие советы

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

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.

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

port = random.randint(10000,60000)

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

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

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

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')

Эфемерные порты в основном лежат в диапазоне 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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top