查找未使用的本地端口的最简单方法是什么?
目前我正在使用类似的东西:
port=$RANDOM
quit=0
while [ "$quit" -ne 1 ]; do
netstat -a | grep $port >> /dev/null
if [ $? -gt 0 ]; then
quit=1
else
port=`expr $port + 1`
fi
done
感觉非常迂回,所以我想知道是否有更简单的路径,例如我错过的内置路径。
答案1
我的解决方案是绑定到端口 0,这要求内核从 ip_local_port_range 分配一个端口。然后,关闭套接字并在配置中使用该端口号。
这是可行的,因为内核似乎不会重用端口号,除非绝对必要。后续绑定到端口 0 将分配不同的端口号。 Python代码:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 0))
addr = s.getsockname()
print(addr[1])
s.close()
这仅给出端口号,例如。60123
。
运行该程序 10 000 次(您应该同时运行这些程序),您将获得 10 000 个不同的端口号。因此,我认为使用这些端口是相当安全的。
答案2
如果您的应用程序支持,您可以尝试将端口 0 传递给应用程序。如果您的应用程序将其传递给内核,则该端口将在请求时动态分配,并保证不会被使用(如果所有端口已被使用,则分配将失败)。
否则,您可以手动执行此操作。您答案中的脚本存在竞争条件,避免它的唯一方法是通过尝试打开它来自动检查它是否打开。如果端口正在使用,程序应该退出并无法打开端口。
例如,假设您正在尝试使用 GNU netcat 进行监听。
#!/bin/bash
read lower_port upper_port < /proc/sys/net/ipv4/ip_local_port_range
while :; do
for (( port = lower_port ; port <= upper_port ; port++ )); do
nc -l -p "$port" 2>/dev/null && break 2
done
done
答案3
单线
我整理了一个很好的单行代码,可以快速达到目的,允许抓取任意范围内的任意数量的端口(为了便于阅读,这里将其分为 4 行):
comm -23 \
<(seq "$FROM" "$TO" | sort) \
<(ss -Htan | awk '{print $4}' | cut -d':' -f2 | sort -u) \
| shuf | head -n "$HOWMANY"
逐行
comm
是一个实用程序,用于比较两个文件中必须按字母顺序排列的行。它输出三列:仅出现在第一个文件中的行、仅出现在第二个文件中的行和公共行。通过指定,-23
我们抑制后面的列,只保留第一列。我们可以用它来获得两个集合的差异,表示为文本行序列。我了解到comm
这里。
第一个文件是我们可以选择的端口范围。生成从到 的seq
已排序数字序列。结果按字母顺序排序(而不是按数字排序,以便符合要求)并使用管道作为第一个文件$FROM
$TO
comm
comm
流程替代。
第二个文件是经过排序的端口列表,我们通过调用命令获得该ss
列表(-t
表示 TCP 端口,-a
表示所有 - 已建立和正在侦听 - 以及-n
数字 - 不要尝试解析,例如,22
to ssh
)。然后,我们仅选择第四列awk
,其中包含本地地址和端口。我们使用分隔cut
符来分割地址和端口:
,只保留后者(-f2
)。然后我们通过不重复的方式来遵守comm
要求。sort
-u
现在我们有了一个开放端口的排序列表,我们可以shuf
使用 来获取第一个"$HOWMANY"
端口head -n
。
例子
抓取私有范围内的三个随机开放端口(49152-65535)
comm -23 <(seq 49152 65535 | sort) <(ss -Htan | awk '{print $4}' | cut -d':' -f2 | sort -u) | shuf | head -n 3
例如可以返回
54930
57937
51399
笔记
- 改为
-t
使用-u
inss
来获取空闲的 UDP 端口。 - 如果您希望获得按数字排序而不是随机排序的可用端口,请替换
shuf
为sort -n
答案4
#!/bin/bash
read LOWERPORT UPPERPORT < /proc/sys/net/ipv4/ip_local_port_range
while :
do
PORT="`shuf -i $LOWERPORT-$UPPERPORT -n 1`"
ss -lpna | grep -q ":$PORT " || break
done
echo $PORT
“ss -lpn” - 将仅显示已建立连接的端口。我们
也应该使用“ss -lpna”来考虑监听端口
归功于克里斯·唐恩