由於在評論@rodrigo建議,我已經結束了與此代碼:
import platform
import re
import subprocess
from typing import Set
if platform.system() == 'Windows':
def _get_ports(pid):
sp = subprocess.run(['netstat', '-anop', 'TCP'],
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
check=True)
rx_socket = re.compile(br'''(?x)^
\s* TCP
\s+ 127.0.0.1 : (?P<port>\d{1,5})
\s+ .*?
\s+ LISTENING
\s+ (?P<pid>\d+)
\s* $''')
for line in sp.stdout.splitlines():
rxm = rx_socket.match(line)
if rxm is None:
continue
sock_port, sock_pid = map(int, rxm.groups())
if sock_pid == pid:
yield sock_port
else:
def _get_ports(pid):
sp = subprocess.run(['lsof', '-anlPFn', '+w',
f'-p{pid}', '[email protected]', '-sTCP:LISTEN'],
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
check=True)
for line in sp.stdout.splitlines():
if line.startswith(b'n'):
host, port = line.rsplit(b':', 1)
port = int(port)
yield port
def get_ports(pid: int) -> Set[int]:
"""Get set of local-bound listening TCPv4 ports for given process.
:param pid: process ID to inspect
:returns: set of ports
"""
return set(_get_ports(pid))
print(get_ports(12345))
它可以在Linux,MacOS和Windows中,並找出給定的過程,都是本地綁定TCPv4端口在LISTEN狀態。它還會跳過各種主機/端口/用戶名反向查找,使其更快,並且不需要提升權限。因此,最終的想法是讓Appium(或其他)在0.0.0.0:0
上啓動,它將自己綁定到OS提供的第一個可用端口,然後檢查它正在監聽的端口。沒有比賽條件。
你也許可以選擇一個隨機端口,將它傳遞給Appium,然後檢查是否有正確的錯誤消息。 –
難道你不能嘗試一個任意的端口,如果它返回'EADDRINUSE'增加它並循環,直到你找到一個免費的端口? – rodrigo
@AlexHall,這是我現在正在做的。然而,問題是關於「正確的方式」 - 例如有沒有辦法爲子流程保留一個端口號? – toriningen