优化查找空闲端口的逻辑,增加随机尝试次数和错误提示
This commit is contained in:
parent
5f0af2ed80
commit
641f212400
@ -1,46 +1,76 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# 查找空闲端口
|
|
||||||
|
# 查找随机空闲端口
|
||||||
|
# 用途:
|
||||||
|
# 在指定端口范围内,随机选择一个当前未被监听(TCP/UDP)的端口
|
||||||
|
# 参数:
|
||||||
|
# $1: 起始端口(默认 10001)
|
||||||
|
# $2: 结束端口(默认 65535)
|
||||||
|
# $3: 最大随机尝试次数(默认 100)
|
||||||
find_free_port() {
|
find_free_port() {
|
||||||
local start="${1:-10001}"
|
local start="${1:-10001}"
|
||||||
local max="${2:-65535}"
|
local max="${2:-65535}"
|
||||||
|
local attempts="${3:-100}"
|
||||||
|
|
||||||
# 收集当前监听端口(TCP + UDP)
|
# ------------------------------------------------------------
|
||||||
|
# 收集当前正在监听的端口(TCP + UDP)
|
||||||
|
# 优先使用 ss,其次 netstat
|
||||||
|
# ------------------------------------------------------------
|
||||||
local used_ports raw
|
local used_ports raw
|
||||||
if command -v ss >/dev/null 2>&1; then
|
if command -v ss >/dev/null 2>&1; then
|
||||||
|
# ss 输出示例:
|
||||||
|
# LISTEN 0 128 0.0.0.0:22
|
||||||
raw=$(ss -lntu 2>/dev/null || true)
|
raw=$(ss -lntu 2>/dev/null || true)
|
||||||
used_ports=$(printf "%s\n" "$raw" | awk '{print $5}' | sed -n '2,$p' | sed -E 's/.*[:]//g' | sed '/^$/d')
|
used_ports=$(printf "%s\n" "$raw" \
|
||||||
|
| awk '{print $5}' \
|
||||||
|
| sed -E 's/.*[:]//g')
|
||||||
elif command -v netstat >/dev/null 2>&1; then
|
elif command -v netstat >/dev/null 2>&1; then
|
||||||
|
# netstat 输出示例:
|
||||||
|
# tcp 0 0 0.0.0.0:22
|
||||||
raw=$(netstat -lntu 2>/dev/null || true)
|
raw=$(netstat -lntu 2>/dev/null || true)
|
||||||
used_ports=$(printf "%s\n" "$raw" | awk '{print $4}' | sed -n '2,$p' | sed -E 's/.*[:]//g' | sed '/^$/d')
|
used_ports=$(printf "%s\n" "$raw" \
|
||||||
elif command -v lsof >/dev/null 2>&1; then
|
| awk '{print $4}' \
|
||||||
raw=$(lsof -i -P -n 2>/dev/null || true)
|
| sed -E 's/.*[:]//g')
|
||||||
used_ports=$(printf "%s\n" "$raw" | awk '/LISTEN/ {print $9}' | sed -E 's/.*[:]//g' | sed '/^$/d')
|
|
||||||
else
|
else
|
||||||
echo "Error: neither ss, netstat nor lsof is available to check listening ports." >&2
|
echo "Error: ss or netstat is required to check listening ports." >&2
|
||||||
return 2
|
return 2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 用关联数组记录已占用端口(需要 bash 4+)
|
# ------------------------------------------------------------
|
||||||
|
# 将已占用端口存入关联数组,便于 O(1) 判断
|
||||||
|
# 需要 bash 4+
|
||||||
|
# ------------------------------------------------------------
|
||||||
declare -A used_map
|
declare -A used_map
|
||||||
local p
|
local p
|
||||||
for p in $used_ports; do
|
for p in $used_ports; do
|
||||||
# 过滤掉非数字
|
# 过滤非数字字段(如 *、:::)
|
||||||
if [[ $p =~ ^[0-9]+$ ]]; then
|
if [[ $p =~ ^[0-9]+$ ]]; then
|
||||||
used_map["$p"]=1
|
used_map["$p"]=1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# 从 start 到 max 逐个检查
|
# ------------------------------------------------------------
|
||||||
for ((port = start; port <= max; port++)); do
|
# 随机尝试若干次
|
||||||
|
# 每次随机生成一个端口,只要未被监听就立即返回
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
local port i
|
||||||
|
for ((i=0; i<attempts; i++)); do
|
||||||
|
# 在 [start, max] 范围内生成随机端口
|
||||||
|
port=$(( RANDOM % (max - start + 1) + start ))
|
||||||
|
|
||||||
|
# 如果端口不在已监听表中,则认为可用
|
||||||
if [[ -z "${used_map[$port]}" ]]; then
|
if [[ -z "${used_map[$port]}" ]]; then
|
||||||
echo "$port"
|
echo "$port"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# 没找到可用端口
|
# ------------------------------------------------------------
|
||||||
echo "Error: No available port found in range $start-$max" >&2
|
# 多次随机尝试后仍未找到可用端口
|
||||||
|
# 通常意味着端口范围过小或已被大量占用
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
echo "Error: no free port found after $attempts random attempts." >&2
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user