查找未使用的本地端口的最简单方法是什么?

查找未使用的本地端口的最简单方法是什么?

查找未使用的本地端口的最简单方法是什么?

目前我正在使用类似的东西:

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$TOcommcomm流程替代

第二个文件是经过排序的端口列表,我们通过调用命令获得该ss列表(-t表示 TCP 端口,-a表示所有 - 已建立和正在侦听 - 以及-n数字 - 不要尝试解析,例如,22to 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使用-uinss来获取空闲的 UDP 端口。
  • 如果您希望获得按数字排序而不是随机排序的可用端口,请替换shufsort -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”来考虑监听端口

归功于克里斯·唐恩

相关内容