Получить открытый порт TCP в Python
Я хочу получить любой случайный открытый порт TCP на локальном хосте в Python. Какой самый простой способ?
5 ответов
Мое текущее решение:
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)
Конечно, это даже более склонно к коллизиям, чем ваш код. Но у меня никогда не было проблем с этим. Дело в том, что в любой момент времени большинство из этих портов с высоким номером не используются, и если вы просто выберете один случайным образом, конфликт с другим процессом маловероятен. Если вы делаете что-то наподобие решения, которое вы опубликовали в своем ответе (открывая сокет и захватывая номер его порта), почти наверняка порт не будет конфликтовать. Поэтому, если это то, что вы будете использовать только для себя (в отличие от того, что вы собираетесь опубликовать для публики), подумайте, стоит ли придумывать действительно пуленепробиваемое решение. Скорее всего, это никогда не будет иметь значения.
По мотивам комментария Марсело Кантоса к вашему вопросу я добавлю, что стандартное решение в подобных случаях заключается в том, чтобы процесс, использующий порт, привязывался к нему, а затем передавал эту информацию любой другой программе, которая в этом нуждается. Как правило, это будет делать что-то вроде записи временного файла, содержащего номер порта, в какое-то стандартное место в файловой системе. Поскольку процесс, с которым вы работаете, этого не делает, в каком-то смысле любое решение, которое вы придумали, будет чем-то вроде хака. Но опять же, если это только для вашего собственного использования, это, вероятно, хорошо.
Это моя версия, однако она не очень случайна, если указать диапазон портов. Это также пострадает от условий гонки, но это лучший способ, который я знаю, если вам нужно знать порт заранее.
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