myb*_*ael 78 shell networking shell-script netstat
查找未使用的本地端口的最简单方法是什么?
目前我正在使用类似的东西:
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
Run Code Online (Sandbox Code Playgroud)
感觉非常迂回,所以我想知道是否有更简单的路径,例如我错过的内置函数。
小智 66
我的解决方案是绑定到端口 0,它要求内核从它的 ip_local_port_range 分配一个端口。然后,关闭套接字并在您的配置中使用该端口号。
这是有效的,因为内核似乎不会重用端口号,直到它绝对必须。后续绑定到端口 0 将分配不同的端口号。蟒蛇代码:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 0))
addr = s.getsockname()
print addr[1]
s.close()
Run Code Online (Sandbox Code Playgroud)
这仅给出了一些端口,例如。60123
.
运行这个程序 10 000 次(你应该同时运行它们),你会得到 10 000 个不同的端口号。因此,我认为使用端口是非常安全的。
Chr*_*own 38
如果您的应用程序支持它,您可以尝试将端口 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
Run Code Online (Sandbox Code Playgroud)
ste*_*ino 23
我已经整理了一个很好的单行代码,可以快速达到目的,允许在任意范围内获取任意数量的端口(这里分为 4 行以提高可读性):
comm -23 \
<(seq "$FROM" "$TO" | sort) \
<(ss -Htan | awk '{print $4}' | cut -d':' -f2 | sort -u) \
| shuf | head -n "$HOWMANY"
Run Code Online (Sandbox Code Playgroud)
comm
是一个实用程序,用于比较必须按字母顺序排列的两个文件中的行。它输出三列:仅出现在第一个文件中的行、仅出现在第二个文件中的行和公共行。通过指定-23
我们抑制后一列,只保留第一列。我们可以使用它来获得两个集合的差异,表示为文本行序列。我是从comm
这里了解到的。
第一个文件是我们可以选择的端口范围。seq
生成从$FROM
到的有序数字序列$TO
。结果按字母顺序(而不是数字顺序,以符合comm
s 要求)排序,并comm
使用进程替换作为第一个文件传输。
第二个文件是端口的排序列表,我们通过调用ss
命令获得它(-t
意味着 TCP 端口,-a
意味着所有 - 已建立和正在侦听 - 和-n
数字 - 不要尝试解析,例如,22
to ssh
)。然后我们只选择带有 的第四列awk
,其中包含本地地址和端口。我们使用分隔符cut
分割地址和端口,:
只保留后者 ( -f2
)。然后我们comm
通过sort
ing 不重复来遵守的要求-u
。
现在我们的开放端口排序列表,我们可以shuf
FLE来再抢第一"$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
Run Code Online (Sandbox Code Playgroud)
例如可以返回
54930
57937
51399
Run Code Online (Sandbox Code Playgroud)
-t
到-u
inss
以获得免费的 UDP 端口。shuf
用sort -n
,如果你喜欢以获取可用的端口,而不是数字排序的随机小智 12
#!/bin/bash
read LOWERPORT UPPERPORT < /proc/sys/net/ipv4/ip_local_port_range
while :
do
PORT="`shuf -i $LOWERPORT-$UPPERPORT -n 1`"
ss -lpn | grep -q ":$PORT " || break
done
echo $PORT
Run Code Online (Sandbox Code Playgroud)
归功于 Chris Down
San*_*eep 11
显然,TCP 连接可以在 bash/zsh 中用作linux 上的文件描述符。以下函数使用该技术并且应该比调用 netcat/telnet 更快。
function EPHEMERAL_PORT() {
LOW_BOUND=49152
RANGE=16384
while true; do
CANDIDATE=$[$LOW_BOUND + ($RANDOM % $RANGE)]
(echo "" >/dev/tcp/127.0.0.1/${CANDIDATE}) >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo $CANDIDATE
break
fi
done
}
Run Code Online (Sandbox Code Playgroud)
使用说明:将输出绑定到一个变量并在脚本中使用。在 Ubuntu 16.04 上测试
root@ubuntu:~> EPHEMERAL_PORT
59453
root@ubuntu:~> PORT=$(EPHEMERAL_PORT)
Run Code Online (Sandbox Code Playgroud)
这是一个跨平台、高效的“oneliner”,它包含所有使用中的端口,并为您提供 3000 个以后的第一个可用端口:
netstat -aln | awk '
$6 == "LISTEN" {
if ($4 ~ "[.:][0-9]+$") {
split($4, a, /[:.]/);
port = a[length(a)];
p[port] = 1
}
}
END {
for (i = 3000; i < 65000 && p[i]; i++){};
if (i == 65000) {exit 1};
print i
}
'
Run Code Online (Sandbox Code Playgroud)
您可以简单地加入所有行以将其放在一行上。如果您想从不同的端口号获得第一个可用的,请将分配更改为i
在for
循环中。
它适用于 Mac 和 Linux,这[:.]
就是需要正则表达式的原因。
小智 5
这是我使用的版本:
while
port=$(shuf -n 1 -i 49152-65535)
netstat -atun | grep -q "$port"
do
continue
done
echo "$port"
Run Code Online (Sandbox Code Playgroud)
该命令shuf -n 1 -i 49152-65535
为您提供动态范围内的“随机”端口。如果已使用,则尝试该范围内的另一个端口。
该命令会netstat -atun
列出所有 (-a) TCP (-t) 和 UDP (-u) 端口,而不会浪费时间来确定主机名 (-n)。