diff --git a/start.sh b/start.sh index c6640ed..66755ce 100755 --- a/start.sh +++ b/start.sh @@ -52,6 +52,38 @@ port_is_open() { ( : >/dev/tcp/127.0.0.1/"${port}" ) 2>/dev/null } +list_port_pids() { + local port="$1" + + if command -v fuser >/dev/null 2>&1; then + fuser -n tcp "${port}" 2>/dev/null || true + return 0 + fi + + if command -v lsof >/dev/null 2>&1; then + lsof -t -iTCP:"${port}" -sTCP:LISTEN 2>/dev/null || true + return 0 + fi + + if command -v ss >/dev/null 2>&1; then + ss -ltnp 2>/dev/null \ + | awk -v port=":${port}" 'NR > 1 && $4 ~ (port "$") { print }' \ + | sed -n 's/.*pid=\([0-9][0-9]*\).*/\1/p' \ + | sort -u + return 0 + fi + + if command -v netstat >/dev/null 2>&1; then + netstat -ltnp 2>/dev/null \ + | awk -v port=":${port}" 'NR > 2 && $4 ~ (port "$") { print $7 }' \ + | sed -n 's#^\([0-9][0-9]*\)/.*#\1#p' \ + | sort -u + return 0 + fi + + return 1 +} + wait_for_port() { local port="$1" local attempts="${2:-20}" @@ -68,6 +100,7 @@ wait_for_port() { stop_port_listener() { local port="$1" local pids="" + local kill_mode="" if ! port_is_open "${port}"; then log "端口 ${port} 当前未被占用" @@ -75,18 +108,29 @@ stop_port_listener() { fi if command -v fuser >/dev/null 2>&1; then - pids="$(fuser -n tcp "${port}" 2>/dev/null || true)" - log "关闭端口 ${port},占用进程: ${pids:-未知}" - fuser -k -TERM -n tcp "${port}" >/dev/null 2>&1 || true + kill_mode="fuser" elif command -v lsof >/dev/null 2>&1; then - pids="$(lsof -t -iTCP:"${port}" -sTCP:LISTEN 2>/dev/null || true)" - log "关闭端口 ${port},占用进程: ${pids:-未知}" + kill_mode="kill" + elif command -v ss >/dev/null 2>&1 || command -v netstat >/dev/null 2>&1; then + kill_mode="kill" + else + warn "端口 ${port} 被占用,但系统没有 fuser/lsof/ss/netstat,无法自动关闭" + return 1 + fi + + pids="$(list_port_pids "${port}")" + if [[ -z "${pids//[[:space:]]/}" ]]; then + warn "端口 ${port} 被占用,但无法获取占用进程 PID,拒绝继续启动以免误报" + return 1 + fi + + log "关闭端口 ${port},占用进程: ${pids}" + if [[ "${kill_mode}" == "fuser" ]]; then + fuser -k -TERM -n tcp "${port}" >/dev/null 2>&1 || true + else for pid in ${pids}; do kill -TERM "${pid}" 2>/dev/null || true done - else - warn "端口 ${port} 被占用,但系统没有 fuser/lsof,无法自动关闭" - return 1 fi for _ in {1..10}; do @@ -97,7 +141,7 @@ stop_port_listener() { done warn "端口 ${port} 未能在宽限期内释放,尝试强制关闭" - if command -v fuser >/dev/null 2>&1; then + if [[ "${kill_mode}" == "fuser" ]]; then fuser -k -KILL -n tcp "${port}" >/dev/null 2>&1 || true else for pid in ${pids}; do @@ -451,7 +495,7 @@ ensure_release_binary() { start_single_exe() { ensure_release_binary || return 1 - stop_port_listener "${PORT_VALUE}" || true + stop_port_listener "${PORT_VALUE}" || return 1 local runtime_log_dir="${CC_WEB_LOGS_DIR:-${RELEASE_DIR}/logs}" local output_log="${runtime_log_dir}/cc-web-single-exe.out" @@ -519,7 +563,7 @@ main() { fi PORT_VALUE="$(resolve_port)" - stop_port_listener "${PORT_VALUE}" || true + stop_port_listener "${PORT_VALUE}" || fail "无法释放端口 ${PORT_VALUE},已停止启动以避免继续使用旧进程" case "${START_MODE}" in single|release|bun) @@ -547,7 +591,7 @@ $(node_upgrade_hint)" warn "源码方式启动失败,检测到 CentOS 7,回退到 dist-exe single-exe" stop_existing_pm2_app - stop_port_listener "${PORT_VALUE}" || true + stop_port_listener "${PORT_VALUE}" || fail "无法释放端口 ${PORT_VALUE},已停止回退启动以避免继续使用旧进程" start_single_exe || fail "CentOS 7 single-exe 启动失败,请检查 ${RELEASE_ENTRY_PATH} 及日志" log "完成。当前使用 CentOS 7 single-exe。" }