初始化提交

This commit is contained in:
dxin
2025-10-13 11:05:51 +08:00
commit ab171d45bb
301 changed files with 59788 additions and 0 deletions

View File

@@ -0,0 +1,27 @@
#!/bin/bash
#
# 检查本地端口是否在指定超时时间内变为可用
# 用法: ./check_port.sh <port> [timeout]
# 例如: ./check_port.sh 8000 60
#
PORT=${1:-8000}
TIMEOUT=${2:-60}
INTERVAL=5
START_TIME=$(date +%s)
END_TIME=$((START_TIME + TIMEOUT))
echo "开始检测: 端口 $PORT,超时时间 ${TIMEOUT}s每次间隔 ${INTERVAL}s"
while [ $(date +%s) -lt $END_TIME ]; do
if nc -z -w1 localhost "$PORT" 2>/dev/null; then
echo "[$(date '+%F %T')] ✅ 端口 $PORT 已启用"
exit 0
else
echo "[$(date '+%F %T')] ⏳ 端口 $PORT 尚为启动用,等待 ${INTERVAL}s..."
sleep $INTERVAL
fi
done
echo "[$(date '+%F %T')] ❌ 超时: 端口 $PORT${TIMEOUT}s 内未变为启用"
exit 1

View File

@@ -0,0 +1,170 @@
pipeline {
agent any
tools{
go 'go1.24.0'
}
environment {
REMOTE_HOST_A = "43.153.98.191"
REMOTE_HOST_B = "49.51.41.243"
NGINX_HOST = "49.51.46.148"
REMOTE_PROJECT_PATH_A = "/data/webapps/go_lessie_sourcing_api"
REMOTE_PROJECT_PATH_B = "/data/webapps/go_lessie_sourcing_api"
NGINX_GO_backend_A = "10.0.0.10"
NGINX_GO_backend_B = "10.0.0.8"
PORT_A = "8100"
PORT_B = "8100"
CONNECTION_TIMEOUT = "600" // 等待连接关闭的超时时间
CHECK_PORT_SCRIPT = "/data/sh/check_port.sh" // 检查服务所运行的端口是否起起来
NGINX_RELOAD_SCRIPT = "/data/sh/set_prod_go_backend_weight.sh" // 设置nginx后端组up/down
SEND_STOP_GOAPP_SCRIPT = "/data/sh/send_stop_goapp.sh" // 发送GO的优雅停止信号
WAIT_CONNECTIONS_SCRIPT = "/data/sh/wait_for_connections.sh" // 监测实例A是否有连接
CHECK_STATUS_SCRIPT = "/data/sh/check_s1_backend_status.sh" // 检查后端组状态
}
stages {
stage('Checkout 代码') {
steps {
echo "阶段一"
git branch: "${params.Code_branch}", credentialsId: 'fly_gitlab_auth', url: 'http://172.24.16.20/go/lessie-sourcing-api.git'
}
}
stage('依赖并构建') {
steps {
echo "阶段二"
sh """
cd ${WORKSPACE}/
export GOVCS="git.deeplink.media:git,*:git"
echo "拉依赖"
go mod tidy -v -x
echo "构建二进制文件"
make build-linux
chmod +x ./build/lessie-sourcing-api
"""
}
}
stage('A脱离&下线') {
steps {
echo "阶段三"
echo "将实例A的nginx权重设置为down停止接收新连接"
sh "ssh ${NGINX_HOST} 'sh ${NGINX_RELOAD_SCRIPT} ${NGINX_GO_backend_A} ${PORT_A} down'"
sh """
ssh ${REMOTE_HOST_A} '
echo "向实例A发送优雅关闭信号"
sh ${SEND_STOP_GOAPP_SCRIPT}
echo "监测实例A是否有连接"
sh ${WAIT_CONNECTIONS_SCRIPT} ${PORT_A} ${CONNECTION_TIMEOUT}
'
"""
}
}
stage('A同步&启动') {
steps {
echo "阶段四"
sh """
echo "进入jenkins工作目录:${WORKSPACE}"
cd ${WORKSPACE}/
echo "同步二进制产物"
rsync -avzuP ./build/lessie-sourcing-api ./configs/application_prod.yaml ${REMOTE_HOST_A}:${REMOTE_PROJECT_PATH_A}/
ssh ${REMOTE_HOST_A} '
cd ${REMOTE_PROJECT_PATH_A}
chmod +x ./lessie-sourcing-api
nohup env ENV=prod ./lessie-sourcing-api > ./go.log 2>&1 &
'
"""
}
}
stage('探测A服务 ') {
steps {
echo "阶段五"
sh "sleep 10"
sh """
ssh ${REMOTE_HOST_A} '
echo "查看实例A的启动日志"
head -n 5 ${REMOTE_PROJECT_PATH_A}/go.log || true
sh ${CHECK_PORT_SCRIPT} 8100 60
ps aux|grep lessie-sourcing-api
'
"""
}
}
stage('恢复A流量') {
steps {
echo "阶段六"
echo "恢复实例A的流量"
sh "sleep 5"
sh "ssh ${NGINX_HOST} 'sh ${NGINX_RELOAD_SCRIPT} ${NGINX_GO_backend_A} ${PORT_A} up'"
echo "实例 A 部署完成"
}
}
stage('B脱离后端组') {
steps {
echo "阶段七"
echo "将实例B的nginx权重设置为down停止接收新连接"
sh "ssh ${NGINX_HOST} 'sh ${NGINX_RELOAD_SCRIPT} ${NGINX_GO_backend_B} ${PORT_B} down'"
sh """
ssh ${REMOTE_HOST_B} '
echo "向实例B发送优雅关闭信号"
sh ${SEND_STOP_GOAPP_SCRIPT}
echo "监测实例B是否有连接"
sh ${WAIT_CONNECTIONS_SCRIPT} ${PORT_B} ${CONNECTION_TIMEOUT}
'
"""
}
}
stage('B同步&启动') {
steps {
echo "阶段八"
sh """
echo "进入jenkins工作目录:${WORKSPACE}"
cd ${WORKSPACE}/
echo "同步二进制产物"
rsync -avzuP ./build/lessie-sourcing-api ./configs/application_prod.yaml ${REMOTE_HOST_B}:${REMOTE_PROJECT_PATH_B}/
ssh ${REMOTE_HOST_B} '
cd ${REMOTE_PROJECT_PATH_B}
chmod +x ./lessie-sourcing-api
nohup env ENV=prod ./lessie-sourcing-api > ./go.log 2>&1 &
'
"""
}
}
stage('探测B服务 ') {
steps {
echo "阶段九"
echo "探测B服务"
sh "sleep 10"
sh """
ssh ${REMOTE_HOST_B} '
echo "查看实例B的启动日志"
head -n 5 ${REMOTE_PROJECT_PATH_B}/go.log || true
sh ${CHECK_PORT_SCRIPT} 8100 60
ps aux|grep lessie-sourcing-api
'
"""
}
}
stage('恢复B流量') {
steps {
echo "阶段十"
echo "恢复实例A的流量"
sh "sleep 5"
sh "ssh ${NGINX_HOST} 'sh ${NGINX_RELOAD_SCRIPT} ${NGINX_GO_backend_B} ${PORT_B} up'"
echo "实例 B 部署完成"
}
}
}
post {
success {
echo '✅ 部署成功!'
}
failure {
echo '❌ 部署失败,请检查日志!'
}
}
}

View File

@@ -0,0 +1,97 @@
pipeline {
agent any
tools{
go 'go1.23.0'
}
environment {
REMOTE_HOST_A = "43.130.56.138"
REMOTE_PROJECT_PATH_A = "/data/webapps/go_lessie_sourcing_api"
PORT_A = "8100"
CONNECTION_TIMEOUT = "600" // 等待连接关闭的超时时间
CHECK_PORT_SCRIPT = "/data/sh/check_port.sh" // 检查服务所运行的端口是否起起来
SEND_STOP_GOAPP_SCRIPT = "/data/sh/send_stop_goapp.sh" // 发送GO的优雅停止信号
WAIT_CONNECTIONS_SCRIPT = "/data/sh/wait_for_connections.sh" // 监测实例A是否有连接
}
stages {
stage('Checkout代码') {
steps {
echo "阶段一"
git branch: "${params.Code_branch}", credentialsId: 'fly_gitlab_auth', url: 'http://172.24.16.20/go/lessie-sourcing-api.git'
}
}
stage('依赖&构建') {
steps {
echo "阶段二"
sh """
cd ${WORKSPACE}/
export GOVCS="git.deeplink.media:git,*:git"
echo "拉依赖"
go mod tidy -v -x
echo "构建二进制文件"
make build-linux
chmod +x ./build/lessie-sourcing-api
"""
}
}
stage('A同步') {
steps {
echo "阶段三"
sh """
echo "进入jenkins工作目录:${WORKSPACE}"
cd ${WORKSPACE}/
echo "同步二进制产物"
rsync -avzuP ./build/lessie-sourcing-api ./configs/application_s1.yaml ${REMOTE_HOST_A}:${REMOTE_PROJECT_PATH_A}/
"""
}
}
stage('A下线') {
steps {
echo "阶段三"
sh """
ssh ${REMOTE_HOST_A} '
echo "向实例A发送优雅关闭信号"
sh ${SEND_STOP_GOAPP_SCRIPT}
echo "监测实例A是否有连接"
sh ${WAIT_CONNECTIONS_SCRIPT} ${PORT_A} ${CONNECTION_TIMEOUT}
'
"""
}
}
stage('A启动') {
steps {
echo "阶段四"
sh """
ssh ${REMOTE_HOST_A} '
cd ${REMOTE_PROJECT_PATH_A}
chmod +x ./lessie-sourcing-api
nohup env ENV=s1 ./lessie-sourcing-api > ./go.log 2>&1 &
'
"""
}
}
stage('探测A服务 ') {
steps {
echo "阶段五"
sh "sleep 10"
sh """
ssh ${REMOTE_HOST_A} '
echo "查看实例A的启动日志"
head -n 5 ${REMOTE_PROJECT_PATH_A}/go.log || true
sh ${CHECK_PORT_SCRIPT} 8100 60
sleep 5
ps aux|grep lessie-sourcing-api
'
"""
}
}
}
post {
success {
echo '✅ 部署成功!'
}
failure {
echo '❌ 部署失败,请检查日志!'
}
}
}

View File

@@ -0,0 +1,97 @@
pipeline {
agent any
tools{
go 'go1.24.0'
}
environment {
REMOTE_HOST_A = "43.159.145.241"
REMOTE_PROJECT_PATH_A = "/data/webapps/go_lessie_sourcing_api"
PORT_A = "8100"
CONNECTION_TIMEOUT = "600" // 等待连接关闭的超时时间
CHECK_PORT_SCRIPT = "/data/sh/check_port.sh" // 检查服务所运行的端口是否起起来
SEND_STOP_GOAPP_SCRIPT = "/data/sh/send_stop_goapp.sh" // 发送GO的优雅停止信号
WAIT_CONNECTIONS_SCRIPT = "/data/sh/wait_for_connections.sh" // 监测实例A是否有连接
}
stages {
stage('Checkout代码') {
steps {
echo "阶段一"
git branch: "${params.Code_branch}", credentialsId: 'fly_gitlab_auth', url: 'http://172.24.16.20/go/lessie-sourcing-api.git'
}
}
stage('依赖&构建') {
steps {
echo "阶段二"
sh """
cd ${WORKSPACE}/
export GOVCS="git.deeplink.media:git,*:git"
echo "拉依赖"
go mod tidy -v -x
echo "构建二进制文件"
make build-linux
chmod +x ./build/lessie-sourcing-api
"""
}
}
stage('A同步') {
steps {
echo "阶段三"
sh """
echo "进入jenkins工作目录:${WORKSPACE}"
cd ${WORKSPACE}/
echo "同步二进制产物"
rsync -avzuP ./build/lessie-sourcing-api ./configs/application_s2.yaml ${REMOTE_HOST_A}:${REMOTE_PROJECT_PATH_A}/
"""
}
}
stage('A下线') {
steps {
echo "阶段三"
sh """
ssh ${REMOTE_HOST_A} '
echo "向实例A发送优雅关闭信号"
sh ${SEND_STOP_GOAPP_SCRIPT}
echo "监测实例A是否有连接"
sh ${WAIT_CONNECTIONS_SCRIPT} ${PORT_A} ${CONNECTION_TIMEOUT}
'
"""
}
}
stage('A启动') {
steps {
echo "阶段四"
sh """
ssh ${REMOTE_HOST_A} '
cd ${REMOTE_PROJECT_PATH_A}
chmod +x ./lessie-sourcing-api
nohup env ENV=s2 ./lessie-sourcing-api > ./go.log 2>&1 &
'
"""
}
}
stage('探测A服务 ') {
steps {
echo "阶段五"
sh "sleep 10"
sh """
ssh ${REMOTE_HOST_A} '
echo "查看实例A的启动日志"
head -n 5 ${REMOTE_PROJECT_PATH_A}/go.log || true
sh ${CHECK_PORT_SCRIPT} 8100 60
sleep 5
ps aux|grep lessie-sourcing-api
'
"""
}
}
}
post {
success {
echo '✅ 部署成功!'
}
failure {
echo '❌ 部署失败,请检查日志!'
}
}
}

View File

@@ -0,0 +1,76 @@
# 线上的 =========================================================
#!/bin/bash
APP_NAME="lessie-sourcing-api"
MAX_WAIT_SECONDS=600
# 1. 获取 PID
PID=$(ps -ef | grep "${APP_NAME}" | grep -v grep | awk '{print $2}' | head -n 1)
if [ -z "$PID" ]; then
echo "未找到 ${APP_NAME} 进程,无需停止"
exit 0
fi
echo "找到进程 PID: $PID"
# 2. 发送 SIGTERM
kill -TERM $PID
echo "已发送 SIGTERM"
# # 3. 等待退出
# ELAPSED=0
# while [ $ELAPSED -lt $MAX_WAIT_SECONDS ]; do
# if ! ps -p $PID > /dev/null 2>&1; then
# echo "进程已退出"
# exit 0
# fi
# sleep 10
# ELAPSED=$((ELAPSED+10))
# echo "已等待 ${ELAPSED} 秒..."
# done
# # 4. 超时强杀
# echo "超时 ${MAX_WAIT_SECONDS} 秒未退出,强制 kill -9"
# kill -9 $PID
# ps aux|grep $PID
# s2的===================================================
#!/bin/bash
APP_PATTERN="./lessie-sourcing-api$"
PID=$(pgrep -f "$APP_PATTERN")
if [ -z "$PID" ]; then
echo "未找到 lessie-sourcing-api 进程"
exit 0
fi
echo "找到 PID: $PID"
kill -TERM $PID
echo "已发送 SIGTERM"
# s3的===================================================
#!/bin/bash
APP_PATTERN="./s3-lessie-sourcing-api"
PID=$(pgrep -f "$APP_PATTERN")
if [ -z "$PID" ]; then
echo "未找到 s3-lessie-sourcing-api 进程"
exit 0
fi
echo "找到 PID: $PID"
kill -TERM $PID
echo "已发送 SIGTERM"

View File

@@ -0,0 +1,45 @@
#!/bin/bash
# Nginx 后端服务器上下线脚本
# 用法: set_backend_status.sh <ip> <port> <action>
# 示例:
# set_backend_status.sh 10.0.0.5 7001 down
# set_backend_status.sh 10.0.0.5 7001 up
IP=$1
PORT=$2
ACTION=$3 # down / up
NGINX_CONFIG="/data/tengine/vhosts/app.lessie.ai.conf"
BACKUP_CONFIG="${NGINX_CONFIG}.backup.$(date +%F_%T).bak"
# 参数检查
if [ -z "$IP" ] || [ -z "$PORT" ] || [ -z "$ACTION" ]; then
echo "用法: $0 <ip> <port> <action> (action: down/up)"
exit 1
fi
# 备份
cp -f "$NGINX_CONFIG" "$BACKUP_CONFIG" || {
echo "备份配置失败"
exit 1
}
# 修改
if [ "$ACTION" == "down" ]; then
sed -i "s/\(server[[:space:]]\+$IP:$PORT[[:space:]]*\)weight=[0-9]\+\(.*\)/\1down\2/" "$NGINX_CONFIG"
elif [ "$ACTION" == "up" ]; then
sed -i "s/\(server[[:space:]]\+$IP:$PORT[[:space:]]*\)down\(.*\)/\1weight=10\2/" "$NGINX_CONFIG"
else
echo "无效的 action: $ACTION"
exit 1
fi
# 验证 & 重载
if nginx -t; then
nginx -s reload
echo "✅ 已将 $IP:$PORT 设置为 $ACTION"
rm -f "$BACKUP_CONFIG"
else
echo "❌ 配置检查失败,回滚..."
cp -f "$BACKUP_CONFIG" "$NGINX_CONFIG"
exit 1
fi

View File

@@ -0,0 +1,264 @@
#!/bin/bash
# 等待指定端口的连接数连续3次为0每次间隔5秒
# 使用方法: wait_s1_for_connections.sh <port> <timeout>
# 示例: wait_s1_for_connections.sh 8000 300最多等待300秒
PORT=$1
TIMEOUT=$2
START_TIME=$(date +%s)
END_TIME=$((START_TIME + TIMEOUT))
SUCCESS_COUNT=0 # 连续成功计数
REQUIRED_SUCCESS=3 # 需要连续成功的次数
CHECK_INTERVAL=5 # 每次检测间隔(秒)
if [ -z "$PORT" ]; then
echo "用法: $0 <port> <timeout>"
exit 1
fi
if [ -z "$TIMEOUT" ]; then
TIMEOUT=600 # 默认超时时间600秒
fi
echo "等待端口 $PORT 的连接数连续 $REQUIRED_SUCCESS 次为0每次检测间隔 $CHECK_INTERVAL 秒),超时时间 $TIMEOUT"
while [ $(date +%s) -lt $END_TIME ]; do
# 检测当前连接数
CONNECTIONS=$(netstat -anp | grep :$PORT | grep ESTABLISHED | wc -l)
echo "当前连接数: $CONNECTIONS(检测次数: $SUCCESS_COUNT/$REQUIRED_SUCCESS"
if [ "$CONNECTIONS" -eq 0 ]; then
SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
echo "检测到连接数为0连续成功计数: $SUCCESS_COUNT/$REQUIRED_SUCCESS"
# 达到3次连续成功退出
if [ "$SUCCESS_COUNT" -eq "$REQUIRED_SUCCESS" ]; then
echo "已连续 $REQUIRED_SUCCESS 次(每次间隔 $CHECK_INTERVAL 秒)检测到端口 $PORT 无活跃连接"
exit 0
fi
else
# 连接数不为0重置计数器
SUCCESS_COUNT=0
echo "连接数不为0重置连续成功计数"
fi
# 每次检测后间隔5秒
echo "等待 $CHECK_INTERVAL 秒后进行下一次检测..."
echo "======================"
sleep $CHECK_INTERVAL
done
echo "超时! 端口 $PORT$TIMEOUT 秒内未达到连续 $REQUIRED_SUCCESS 次连接数为0当前连接数: $CONNECTIONS"
exit 1
# === 8月11日 === ↓ ===增加了连接类型过滤和进程实际请求检测======= ↓ =======================================
#!/bin/bash
# 等待AI进程的活跃用户连接为0排除内部连接和无效连接
# 使用方法: wait_for_ai_connections.sh <port> <process_name> <timeout>
# 示例: wait_for_ai_connections.sh 8000 "python server.py" 300
# netstat -anp | grep :8000 | grep ESTABLISHED | wc -l
PORT=$1
PROCESS_NAME=$2 # 进程特征名称,用于精准定位
TIMEOUT=${3:-300} # 默认超时时间300秒
# 参数校验
if [ -z "$PORT" ] || [ -z "$PROCESS_NAME" ]; then
echo "用法: $0 <port> <process_name> <timeout>"
echo "示例: $0 8000 'python server.py' 300"
exit 1
fi
# 配置参数
START_TIME=$(date +%s)
END_TIME=$((START_TIME + TIMEOUT))
SUCCESS_COUNT=0
REQUIRED_SUCCESS=3 # 连续3次检测通过
CHECK_INTERVAL=5 # 检测间隔(秒)
NGINX_IP=$(hostname -I | awk '{print $1}') # Nginx服务器IP排除自身连接
echo "开始检测端口 $PORT 上的进程 '$PROCESS_NAME',超时时间 $TIMEOUT"
echo "将排除与Nginx服务器($NGINX_IP)的内部连接"
# 获取进程ID用于更精准的连接检测
PID=$(ps aux | grep -v grep | grep "$PROCESS_NAME" | grep ":$PORT" | awk '{print $2}')
if [ -z "$PID" ]; then
echo "未找到端口 $PORT 上的进程 '$PROCESS_NAME'"
exit 1
fi
echo "检测到目标进程PID: $PID"
while [ $(date +%s) -lt $END_TIME ]; do
# 1. 检测活跃连接排除Nginx内部连接和TIME_WAIT状态
# 过滤条件:
# - 状态为ESTABLISHED
# - 不包含Nginx服务器IP排除负载均衡器的健康检查连接
# - 属于目标进程PID
CONNECTIONS=$(netstat -antp | grep -E ":$PORT.*ESTABLISHED" | grep -v "$NGINX_IP" | grep "$PID" | wc -l)
# 2. 检测进程是否有近期请求日志(如果日志有时间戳)
# 检查最近30秒内是否有新请求
RECENT_LOGS=0
LOG_FILE=$(find /data/webapps/ -name "lessie_sourcing_agents_*.log" | sort -r | head -1)
if [ -n "$LOG_FILE" ]; then
RECENT_LOGS=$(tail -n 100 "$LOG_FILE" | grep -E "$(date -d '30 seconds ago' +'%Y-%m-%d %H:%M:%S')" -A 100 | grep -i "request" | wc -l)
fi
echo "=== 检测结果 ==="
echo "活跃用户连接数: $CONNECTIONS排除Nginx内部连接"
echo "最近30秒请求数: $RECENT_LOGS"
echo "连续无连接计数: $SUCCESS_COUNT/$REQUIRED_SUCCESS"
echo "================="
# 判断条件:无活跃连接且无近期请求
if [ "$CONNECTIONS" -eq 0 ] && [ "$RECENT_LOGS" -eq 0 ]; then
SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
if [ "$SUCCESS_COUNT" -eq "$REQUIRED_SUCCESS" ]; then
echo "已确认进程无活跃用户连接,安全下线"
exit 0
fi
else
SUCCESS_COUNT=0
fi
sleep $CHECK_INTERVAL
done
echo "超时! 进程仍有活动(连接数: $CONNECTIONS,近期请求: $RECENT_LOGS"
exit 1
# -------------------------
#!/bin/bash
# 等待指定端口的连接数连续3次为0每次间隔5秒
# 使用方法: wait_s1_for_connections.sh <port> <timeout>
# 示例: wait_s1_for_connections.sh 8000 300最多等待300秒
PORT=$1
TIMEOUT=$2
START_TIME=$(date +%s)
END_TIME=$((START_TIME + TIMEOUT))
SUCCESS_COUNT=0 # 连续成功计数
REQUIRED_SUCCESS=5 # 需要连续成功的次数
CHECK_INTERVAL=5 # 每次检测间隔(秒)
if [ -z "$PORT" ]; then
echo "用法: $0 <port> <timeout>"
exit 1
fi
if [ -z "$TIMEOUT" ]; then
TIMEOUT=600 # 默认超时时间600秒
fi
echo "等待端口 $PORT 的连接数连续 $REQUIRED_SUCCESS 次为0每次检测间隔 $CHECK_INTERVAL 秒),超时时间 $TIMEOUT"
while [ $(date +%s) -lt $END_TIME ]; do
# 检测当前连接数
CONNECTIONS=$(netstat -anp | grep :$PORT | grep -w ESTABLISHED | wc -l)
echo "当前连接数: $CONNECTIONS(检测次数: $SUCCESS_COUNT/$REQUIRED_SUCCESS"
if [ "$CONNECTIONS" -eq 0 ]; then
SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
echo "检测到连接数为0连续成功计数: $SUCCESS_COUNT/$REQUIRED_SUCCESS"
# 达到3次连续成功退出
if [ "$SUCCESS_COUNT" -eq "$REQUIRED_SUCCESS" ]; then
echo "已连续 $REQUIRED_SUCCESS 次(每次间隔 $CHECK_INTERVAL 秒)检测到端口 $PORT 无活跃连接"
exit 0
fi
else
# 连接数不为0重置计数器
SUCCESS_COUNT=0
echo "连接数不为0重置连续成功计数"
fi
# 每次检测后间隔5秒
echo "等待 $CHECK_INTERVAL 秒后进行下一次检测..."
echo " "
sleep $CHECK_INTERVAL
done
echo "超时! 端口 $PORT$TIMEOUT 秒内未达到连续 $REQUIRED_SUCCESS 次连接数为0当前连接数: $CONNECTIONS"
exit 1
---------------------------------------------
#!/bin/bash
#
# 等待指定端口的连接数连续 N 次为 0每次间隔 M 秒)
# 用法: wait_for_connections.sh <port> [timeout]
# 示例: wait_for_connections.sh 8000 300 # 最多等待 300 秒
#
PORT=$1
TIMEOUT=${2:-600} # 默认超时 600 秒
REQUIRED_SUCCESS=${REQUIRED_SUCCESS:-5} # 需要连续成功次数,默认 5 次
CHECK_INTERVAL=${CHECK_INTERVAL:-5} # 检测间隔,默认 5 秒
START_TIME=$(date +%s)
END_TIME=$((START_TIME + TIMEOUT))
SUCCESS_COUNT=0
if [ -z "$PORT" ]; then
echo "用法: $0 <port> [timeout]"
exit 1
fi
# 检测可用工具
if command -v ss >/dev/null 2>&1; then
NET_TOOL="ss"
elif command -v netstat >/dev/null 2>&1; then
NET_TOOL="netstat"
else
echo "错误: 没有找到 ss 或 netstat 命令"
exit 1
fi
# 获取当前端口 ESTABLISHED 连接数
get_connections() {
if [ "$NET_TOOL" = "ss" ]; then
ss -tanp 2>/dev/null | grep ":$PORT" | grep ESTAB | wc -l
else
netstat -anp 2>/dev/null | grep ":$PORT" | grep -w ESTABLISHED | wc -l
fi
}
echo "开始检测: 端口 $PORT"
echo "条件: 连续 $REQUIRED_SUCCESS 次为 0检测间隔 ${CHECK_INTERVAL}s超时时间 ${TIMEOUT}s"
echo "使用工具: $NET_TOOL"
echo "---------------------------------------------"
while [ $(date +%s) -lt $END_TIME ]; do
CONNECTIONS=$(get_connections)
TIMESTAMP=$(date '+%F %T')
echo "[$TIMESTAMP] 当前连接数: $CONNECTIONS(连续成功 $SUCCESS_COUNT/$REQUIRED_SUCCESS"
if [ "$CONNECTIONS" -eq 0 ]; then
SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
if [ "$SUCCESS_COUNT" -ge "$REQUIRED_SUCCESS" ]; then
echo "[$TIMESTAMP] ✅ 检测通过: 端口 $PORT 已连续 $REQUIRED_SUCCESS 次无活跃连接"
exit 0
fi
else
SUCCESS_COUNT=0
fi
sleep "$CHECK_INTERVAL"
done
TIMESTAMP=$(date '+%F %T')
echo "[$TIMESTAMP] ❌ 超时: 在 ${TIMEOUT}s 内端口 $PORT 未达到连续 $REQUIRED_SUCCESS 次无活跃连接"
exit 1