在日常運維工作中,經常會遇到系統性能莫名跟不上業務需求的情況:服務器響應變慢、應用加載卡頓、資源占用異常飆升等問題頻繁出現,卻難以快速問題根源究竟在CPU過載、內存泄漏、磁盤I/O阻塞還是網絡帶寬瓶頸。這種時候,特別需要一個全面的性能檢測腳本來系統排查——既能實時監控CPU使用率、核心負載、內存占用、swap交換分區等基礎資源指標,又能深入分析磁盤讀寫速度、分區使用率、網絡吞吐量及連接狀態,還能自動比對預設閾值標記異常項,最終生成直觀的檢測報告,幫助快速定位性能瓶頸,為優化系統配置、提升運維效率提供精準依據。
腳本內容:
vi linux_speed_ceshi.sh
添加以下內容
#!/usr/bin/env bash
#
# Description: Offline Server Performance Test with Network Benchmark
# Author: Teddysun (Enhanced for offline use)
# Copyright: (C) 2015 - 2023 Teddysun <i@teddysun.com>
# Modified: 2025-08-01 (No netcat dependency, fixed floating point errors)
#
trap _exit INT QUIT TERM# 顏色輸出函數
_red() { printf '\033[0;31;31m%b\033[0m' "$1"; }
_green() { printf '\033[0;31;32m%b\033[0m' "$1"; }
_yellow() { printf '\033[0;31;33m%b\033[0m' "$1"; }
_blue() { printf '\033[0;31;36m%b\033[0m' "$1"; }# 命令存在性檢查
_exists() {local cmd="$1"command -v "$cmd" >/dev/null 2>&1
}# 退出清理
_exit() {_red "\nScript terminated. Cleaning up...\n"rm -rf benchtest_* network_test# 清理可能的后臺進程if [ -n "$transfer_pid" ]; thenkill $transfer_pid 2>/dev/nullfiexit 1
}# 分隔線
next() {printf "%-70s\n" "-" | sed 's/\s/-/g'
}# 獲取操作系統信息
get_opsy() {[ -f /etc/redhat-release ] && awk '{print $0}' /etc/redhat-release && return[ -f /etc/os-release ] && awk -F'[= "]' '/PRETTY_NAME/{print $3,$4,$5}' /etc/os-release && return[ -f /etc/lsb-release ] && awk -F'[="]+' '/DESCRIPTION/{print $2}' /etc/lsb-release && return
}# 磁盤I/O測試
io_test() {(LANG=C dd if=/dev/zero of=benchtest_$$ bs=512k count=$1 conv=fdatasync && rm -f benchtest_$$) 2>&1 | awk -F, '{io=$NF} END { print io}' | sed 's/^[ \t]*//;s/[ \t]*$//'
}# 容量單位轉換
calc_size() {local raw=$1local total_size=0local num=1local unit="KB"# 使用awk處理浮點數比較if awk -v raw="$raw" 'BEGIN { exit !(raw >= 1073741824) }'; thennum=1073741824unit="TB"elif awk -v raw="$raw" 'BEGIN { exit !(raw >= 1048576) }'; thennum=1048576unit="GB"elif awk -v raw="$raw" 'BEGIN { exit !(raw >= 1024) }'; thennum=1024unit="MB"elif [ "$raw" -eq 0 ]; thenecho "0"returnfitotal_size=$(awk -v raw="$raw" -v num="$num" 'BEGIN{printf "%.1f", raw / num}')echo "${total_size} ${unit}"
}# 速度單位轉換 (Mbps)
calc_bandwidth() {local mbps=$1local total=0local num=1local unit="Mbps"# 使用awk處理浮點數比較if awk -v mbps="$mbps" 'BEGIN { exit !(mbps >= 1000) }'; thennum=1000unit="Gbps"elif [ "$mbps" -eq 0 ]; thenecho "0"returnfitotal=$(awk -v mbps="$mbps" -v num="$num" 'BEGIN{printf "%.2f", mbps / num}')echo "${total} ${unit}"
}# 虛擬化檢測
check_virt() {virt="Unknown"_exists "dmesg" && virtualx="$(dmesg 2>/dev/null)"# Docker/LXC 檢測grep -qa docker /proc/1/cgroup && virt="Docker"grep -qa lxc /proc/1/cgroup && virt="LXC"grep -qa container=lxc /proc/1/environ && virt="LXC"# 其他虛擬化技術[[ -f /proc/user_beancounters ]] && virt="OpenVZ"[[ "${virtualx}" == *kvm-clock* ]] && virt="KVM"[[ "${sys_product}" == *KVM* ]] && virt="KVM"[[ "${cname}" == *KVM* ]] && virt="KVM"[[ "${cname}" == *QEMU* ]] && virt="KVM"[[ "${virtualx}" == *"VMware Virtual Platform"* ]] && virt="VMware"[[ "${sys_product}" == *"VMware Virtual Platform"* ]] && virt="VMware"[[ "${virtualx}" == *"Parallels Software International"* ]] && virt="Parallels"[[ "${virtualx}" == *VirtualBox* ]] && virt="VirtualBox"[[ -e /proc/xen ]] && virt="Xen"[[ "${sys_manu}" == *"Microsoft Corporation"* && "${sys_product}" == *"Virtual Machine"* ]] && {[[ "${sys_ver}" == *"7.0"* || "${sys_ver}" == *"Hyper-V" ]] && virt="Hyper-V" || virt="Microsoft Virtual Machine"}[[ "$virt" == "Unknown" ]] && virt="Dedicated"
}# 獲取系統信息
get_system_info() {cname=$(awk -F: '/model name/ {name=$2} END {print name}' /proc/cpuinfo | sed 's/^[ \t]*//;s/[ \t]*$//')cores=$(awk -F: '/^processor/ {core++} END {print core}' /proc/cpuinfo)freq=$(awk -F'[ :]' '/cpu MHz/ {print $4;exit}' /proc/cpuinfo)ccache=$(awk -F: '/cache size/ {cache=$2} END {print cache}' /proc/cpuinfo | sed 's/^[ \t]*//;s/[ \t]*$//')cpu_aes=$(grep -i 'aes' /proc/cpuinfo)cpu_virt=$(grep -Ei 'vmx|svm' /proc/cpuinfo)# 內存信息tram=$(free -b | awk '/Mem/ {print $2}')tram=$(calc_size $tram)uram=$(free -b | awk '/Mem/ {print $3}')uram=$(calc_size $uram)swap=$(free -b | awk '/Swap/ {print $2}')swap=$(calc_size $swap)uswap=$(free -b | awk '/Swap/ {print $3}')uswap=$(calc_size $uswap)# 運行時間up=$(awk '{a=$1/86400;b=($1%86400)/3600;c=($1%3600)/60} {printf("%d days, %d hour %d min\n",a,b,c)}' /proc/uptime)# 系統負載if _exists "uptime"; thenload=$(uptime | awk -F'load average:' '{print $2}' | sed 's/^[ \t]*//;s/[ \t]*$//')elseload="N/A"fi# 系統信息opsy=$(get_opsy)arch=$(uname -m)lbit=$(getconf LONG_BIT 2>/dev/null || echo ${arch} | grep -q "64" && echo 64 || echo 32)kern=$(uname -r)# 磁盤信息disk_total_size=$(df -t simfs -t ext2 -t ext3 -t ext4 -t btrfs -t xfs -t vfat -t ntfs -t swap --total -B1 2>/dev/null | grep total | awk '{ print $2 }')disk_total_size=$(calc_size $disk_total_size)disk_used_size=$(df -t simfs -t ext2 -t ext3 -t ext4 -t btrfs -t xfs -t vfat -t ntfs -t swap --total -B1 2>/dev/null | grep total | awk '{ print $3 }')disk_used_size=$(calc_size $disk_used_size)# 網絡參數tcpctrl=$(sysctl net.ipv4.tcp_congestion_control 2>/dev/null | awk -F ' ' '{print $3}')# 網絡接口檢測network_interfaces=($(ip link show | awk -F': ' '/^[0-9]+: [^lo]/ {print $2}'))# 網絡接口詳細信息declare -A iface_infofor iface in "${network_interfaces[@]}"; doip_addr=$(ip addr show dev $iface | awk '/inet / {print $2}' | cut -d'/' -f1 | head -n1)mac_addr=$(ip link show dev $iface | awk '/link\/ether/ {print $2}')speed=$(ethtool $iface 2>/dev/null | awk '/Speed:/ {print $2}')iface_info["${iface}_ip"]=$ip_addriface_info["${iface}_mac"]=$mac_addriface_info["${iface}_speed"]=$speeddone
}# 增強的磁盤I/O測試
enhanced_io_test() {local freespace=$(df -m . | awk 'NR==2 {print $4; exit}')[[ -z "$freespace" ]] && freespace=$(df -m . | awk 'NR==3 {print $3; exit}')if awk -v fs="$freespace" 'BEGIN { exit !(fs > 1024) }'; thenlocal test_sizes=(256 512 1024 2048)local test_results=()local test_names=("Small Files (256MB)" "Medium Files (512MB)" "Large Files (1024MB)" "Very Large Files (2048MB)")echo " Performing Enhanced I/O Speed Tests..."for i in "${!test_sizes[@]}"; dosize=${test_sizes[$i]}if awk -v fs="$freespace" -v sz="$size" 'BEGIN { exit !(fs < sz * 2) }'; then_yellow " Skipping ${size}MB test - insufficient space"continuefiresult=$(io_test $((size / 512 * 2)))test_results+=("$result")echo " ${test_names[$i]} : $(_yellow "$result")"done# 計算平均值local total=0local count=0for res in "${test_results[@]}"; dospeed=$(echo $res | awk '{print $1}')total=$(awk -v t="$total" -v s="$speed" 'BEGIN{printf "%.1f", t + s}')((count++))doneif [ $count -gt 0 ]; thenlocal avg=$(awk -v t="$total" -v c="$count" 'BEGIN{printf "%.1f", t / c}')echo " Average I/O Speed : $(_yellow "$avg MB/s")"fielseecho " $(_red "Insufficient disk space for I/O tests!")"fi
}# CPU性能測試
cpu_benchmark() {echo " Running CPU Benchmark (Single Thread)..."local start=$(date +%s)local result=$(dd if=/dev/zero bs=1M count=1000 2>/dev/null | sha256sum)local end=$(date +%s)local duration=$((end - start))if [ $duration -eq 0 ]; thenduration=1filocal speed=$(awk -v cnt="1000" -v dur="$duration" 'BEGIN{printf "%.2f", cnt / dur}')echo " SHA256 Hash Speed : $(_yellow "${speed} MB/s")"echo " Running CPU Benchmark (Multi Thread)..."local cores=$(( $(nproc) ))start=$(date +%s)for ((i=0; i<cores; i++)); dodd if=/dev/zero bs=1M count=1000 2>/dev/null | sha256sum >/dev/null &donewaitend=$(date +%s)duration=$((end - start))if [ $duration -eq 0 ]; thenduration=1fispeed=$(awk -v cnt="1000" -v cores="$cores" -v dur="$duration" 'BEGIN{printf "%.2f", (cnt * cores) / dur}')echo " Multi-Thread Speed : $(_yellow "${speed} MB/s") ($cores cores)"
}# 內存性能測試
memory_benchmark() {echo " Running Memory Benchmark..."# 分配內存并測試寫入速度local mem_size=$(( $(free -m | awk '/Mem/{print $7}') / 2 ))if [ $mem_size -gt 2048 ]; thenmem_size=2048elif [ $mem_size -lt 100 ]; thenmem_size=100fiecho " Testing ${mem_size}MB memory block..."# 寫入速度測試local start=$(date +%s.%N)dd if=/dev/zero of=/dev/shm/memtest bs=1M count=$mem_size conv=fdatasync 2>/dev/nulllocal end=$(date +%s.%N)local duration=$(awk -v s="$start" -v e="$end" 'BEGIN{printf "%.6f", e - s}')local write_speed=$(awk -v sz="$mem_size" -v dur="$duration" 'BEGIN{printf "%.1f", sz / dur}')# 讀取速度測試start=$(date +%s.%N)dd if=/dev/shm/memtest of=/dev/null bs=1M count=$mem_size 2>/dev/nullend=$(date +%s.%N)duration=$(awk -v s="$start" -v e="$end" 'BEGIN{printf "%.6f", e - s}')local read_speed=$(awk -v sz="$mem_size" -v dur="$duration" 'BEGIN{printf "%.1f", sz / dur}')# 清理rm -f /dev/shm/memtestecho " Write Speed : $(_yellow "${write_speed} MB/s")"echo " Read Speed : $(_yellow "${read_speed} MB/s")"
}# 使用socat或bash內置功能創建網絡服務器
start_network_server() {local port=$1local output_file=$2if _exists "socat"; thensocat TCP4-LISTEN:$port,bind=0.0.0.0 OPEN:$output_file,creat,append &return $!elif _exists "bash" && [[ $(bash --version | awk 'NR==1 {print $4}' | cut -d'(' -f1) > "4.3" ]]; then# 使用bash 4.3+的內置TCP監聽功能cat >&"${net_fd}" > "$output_file" &return $!elsereturn 1fi
}# 增強的網絡吞吐量測試(不依賴nc)
network_throughput_test() {local iface=$1local duration=${2:-10} # 默認測試10秒echo " Running Network Throughput Test on $iface for $duration seconds..."# 檢查是否支持ethtoolif _exists "ethtool"; thenlocal speed=$(ethtool $iface 2>/dev/null | awk '/Speed:/ {print $2}')if [ -n "$speed" ]; thenecho " Interface Rated Speed: $(_blue "$speed")"fifi# 準備網絡測試環境local port=$((RANDOM % 1000 + 5000)) # 隨機端口local temp_file=$(mktemp)local transfer_pid=""# 檢查網絡工具可用性if ! _exists "socat" && ! ( _exists "bash" && [[ $(bash --version | awk 'NR==1 {print $4}' | cut -d'(' -f1) > "4.3" ]] ); then_red " No suitable network tools found (socat or bash 4.3+ required). Skipping test."rm -f "$temp_file"return 1fi# 為bash內置TCP功能準備文件描述符if _exists "bash" && [[ $(bash --version | awk 'NR==1 {print $4}' | cut -d'(' -f1) > "4.3" ]]; thenexec {net_fd}<>/dev/tcp/0.0.0.0/$portfi# 啟動接收端start_network_server $port "$temp_file"local server_pid=$!sleep 2 # 等待接收端準備好if ! ps -p $server_pid > /dev/null; then_red " Failed to start network server. Skipping test."rm -f "$temp_file"return 1fi# 獲取接口IPlocal ip=$(ip addr show dev $iface | awk '/inet / {print $2}' | cut -d'/' -f1 | head -n1)if [ -z "$ip" ]; then_red " No IP address found for interface $iface"kill $server_pid 2>/dev/nullrm -f "$temp_file"return 1fi# 啟動發送端,持續指定時間(sleep $duration; pkill -P $$ dd) &local killer_pid=$!dd if=/dev/zero bs=1M 2>/dev/null | {if _exists "socat"; thensocat - TCP4:$ip:$portelsecat >/dev/tcp/$ip/$portfi} >/dev/null 2>&1 &transfer_pid=$!# 等待測試完成wait $killer_pid 2>/dev/nullsleep 1kill $server_pid 2>/dev/nullkill $transfer_pid 2>/dev/null 2>/dev/null# 關閉bash網絡文件描述符if _exists "bash" && [[ $(bash --version | awk 'NR==1 {print $4}' | cut -d'(' -f1) > "4.3" ]]; thenexec {net_fd}>&-fi# 計算傳輸數據量local transferred=$(du -b $temp_file | awk '{print $1}')rm -f $temp_file# 計算吞吐量 (MB/s 和 Mbps)local mb_transferred=$(awk -v t="$transferred" 'BEGIN{printf "%.2f", t / 1048576}')local mbps=$(awk -v t="$transferred" -v d="$duration" 'BEGIN{printf "%.2f", (t * 8) / (1000000 * d)}')local speed=$(calc_bandwidth $mbps)echo " Test Duration : $(_blue "${duration} seconds")"echo " Data Transferred : $(_blue "$(awk -v mbt="$mb_transferred" 'BEGIN{printf "%.2f", mbt / 1024}') GB ($mb_transferred MB)")"echo " Throughput : $(_yellow "$speed") ($(awk -v mbt="$mb_transferred" -v d="$duration" 'BEGIN{printf "%.2f", mbt / d}') MB/s)"return 0
}# 網絡延遲測試
network_latency_test() {local target=$1local count=${2:-10}echo " Running Network Latency Test to $target ($count packets)..."if ! _exists "ping"; then_red " ping command not found, skipping latency test"return 1fi# 執行ping測試local ping_result=$(ping -c $count $target 2>/dev/null)if [ $? -ne 0 ]; then_red " Ping test failed to $target"return 1fi# 提取ping統計信息local min=$(echo "$ping_result" | awk '/rtt/ {print $4}' | cut -d'/' -f1)local avg=$(echo "$ping_result" | awk '/rtt/ {print $4}' | cut -d'/' -f2)local max=$(echo "$ping_result" | awk '/rtt/ {print $4}' | cut -d'/' -f3)local mdev=$(echo "$ping_result" | awk '/rtt/ {print $4}' | cut -d'/' -f4)local packet_loss=$(echo "$ping_result" | awk '/packet loss/ {print $6}')echo " Packet Loss : $(_blue "$packet_loss")"echo " Latency (Min/Avg/Max) : $(_yellow "${min}ms/${avg}ms/${max}ms")"echo " Latency Std Dev : $(_yellow "${mdev}ms")"return 0
}# 增強的離線網絡測試
enhanced_network_test() {echo " Preparing Enhanced Network Test..."# 創建測試文件local test_file_size=100 # MBecho " Generating ${test_file_size}MB test file..."dd if=/dev/zero of=network_test bs=1M count=$test_file_size 2>/dev/null# 檢測可用網絡接口if [ ${#network_interfaces[@]} -eq 0 ]; then_red " No active network interfaces found. Skipping network test."return 1fiecho " Available Network Interfaces:"for iface in "${network_interfaces[@]}"; doecho " - $(_blue "$iface"): ${iface_info["${iface}_ip"]} (${iface_info["${iface}_speed"]:-Unknown speed})"done# 檢查網絡工具if ! _exists "socat" && ! ( _exists "bash" && [[ $(bash --version | awk 'NR==1 {print $4}' | cut -d'(' -f1) > "4.3" ]] ); then_yellow " Warning: Limited network testing available - install socat for full functionality"fi# 選擇主要接口(排除虛擬接口)local main_interface=""for iface in "${network_interfaces[@]}"; doif [[ "$iface" != docker* && "$iface" != br-* && "$iface" != veth* ]]; thenmain_interface="$iface"breakfidoneif [ -z "$main_interface" ]; thenmain_interface="${network_interfaces[0]}"fi# 測試方法選擇echo -e "\nSelect Network Test Method:"echo " 1) Local Loopback Bandwidth Test (Standard)"echo " 2) Interface Throughput Test (Single Interface)"echo " 3) Multi-Thread Loopback Test (Advanced)"echo " 4) Interface-to-Interface Test (Requires 2+ NICs)"echo " 5) Loopback Latency Test"echo " 6) External Server Test (If online, optional)"echo " 7) Skip Network Test"echo -n " Your choice [1-7]: "read choicecase $choice in1)loopback_network_test;;2)echo -n " Enter interface name to test (default: $main_interface): "read ifaceiface=${iface:-$main_interface}echo -n " Enter test duration in seconds (default: 10): "read durationnetwork_throughput_test "$iface" ${duration:-10};;3)multithread_loopback_test;;4)interface_to_interface_test;;5)network_latency_test "127.0.0.1" 30;;6)echo -n " Enter external server IP or hostname to test: "read serverif [ -z "$server" ]; then_red " No server specified, skipping test"elsenetwork_latency_test "$server"echo -n " Run bandwidth test to $server? (y/N): "read run_bwif [[ "$run_bw" =~ ^[Yy]$ ]]; thenexternal_bandwidth_test "$server"fifi;;*)echo " Skipping network test."return 0;;esac
}# 標準回環測試
loopback_network_test() {echo " Starting Loopback Network Test..."# 測試文件大小 (MB)local test_file_size=100# 測試次數local test_runs=3local total_speed=0for ((i=1; i<=test_runs; i++)); doecho " Test $i/$test_runs: Transferring ${test_file_size}MB via loopback..."# 寫入速度測試local start=$(date +%s.%N)dd if=network_test of=/dev/null bs=1M 2>/dev/nulllocal end=$(date +%s.%N)local duration=$(awk -v s="$start" -v e="$end" 'BEGIN{printf "%.6f", e - s}')local speed_mb=$(awk -v sz="$test_file_size" -v dur="$duration" 'BEGIN{printf "%.2f", sz / dur}')local speed_mbps=$(awk -v smb="$speed_mb" 'BEGIN{printf "%.2f", smb * 8.388608}') # MB/s to Mbpslocal speed=$(calc_bandwidth $speed_mbps)echo " Transfer Speed : $(_yellow "${speed} (${speed_mb} MB/s)")"total_speed=$(awk -v t="$total_speed" -v s="$speed_mbps" 'BEGIN{printf "%.2f", t + s}')donelocal avg_speed_mbps=$(awk -v t="$total_speed" -v r="$test_runs" 'BEGIN{printf "%.2f", t / r}')local avg_speed=$(calc_bandwidth $avg_speed_mbps)echo " Average Speed : $(_green "${avg_speed}")"
}# 多線程回環測試
multithread_loopback_test() {echo " Starting Multi-Thread Loopback Test..."# 測試參數local thread_count=4local chunk_size=25 # MBlocal total_size=$((thread_count * chunk_size))echo " Transferring ${total_size}MB using $thread_count threads..."local start=$(date +%s.%N)for ((i=0; i<thread_count; i++)); do{dd if=network_test of=/dev/null bs=1M count=$chunk_size skip=$((i * chunk_size)) 2>/dev/null} &donewaitlocal end=$(date +%s.%N)local duration=$(awk -v s="$start" -v e="$end" 'BEGIN{printf "%.6f", e - s}')local speed_mb=$(awk -v sz="$total_size" -v dur="$duration" 'BEGIN{printf "%.2f", sz / dur}')local speed_mbps=$(awk -v smb="$speed_mb" 'BEGIN{printf "%.2f", smb * 8.388608}') # MB/s to Mbpslocal speed=$(calc_bandwidth $speed_mbps)echo " Total Transferred : $(_yellow "${total_size} MB")"echo " Transfer Duration : $(_yellow "${duration%.*} seconds")"echo " Aggregate Speed : $(_green "${speed} (${speed_mb} MB/s)")"
}# 接口到接口測試
interface_to_interface_test() {echo " Starting Interface-to-Interface Test..."if [ ${#network_interfaces[@]} -lt 2 ]; then_red " Only one network interface found. This test requires at least two interfaces."return 1fi# 檢查網絡工具if ! _exists "socat" && ! ( _exists "bash" && [[ $(bash --version | awk 'NR==1 {print $4}' | cut -d'(' -f1) > "4.3" ]] ); then_red " No suitable network tools found (socat or bash 4.3+ required). Skipping test."return 1fi# 顯示可用接口供選擇echo " Available interfaces:"for i in "${!network_interfaces[@]}"; doecho " $((i+1))) ${network_interfaces[$i]} (${iface_info["${network_interfaces[$i]}_ip"]})"doneecho -n " Select first interface [1]: "read iface1_idxiface1_idx=${iface1_idx:-1}iface1_idx=$((iface1_idx-1))echo -n " Select second interface [2]: "read iface2_idxiface2_idx=${iface2_idx:-2}iface2_idx=$((iface2_idx-1))if [ $iface1_idx -eq $iface2_idx ]; then_red " Interfaces must be different!"return 1filocal iface1="${network_interfaces[$iface1_idx]}"local iface2="${network_interfaces[$iface2_idx]}"echo " Selected Interfaces:"echo " Interface 1: $(_blue "$iface1")"echo " Interface 2: $(_blue "$iface2")"# 獲取接口IPlocal ip1=${iface_info["${iface1}_ip"]}local ip2=${iface_info["${iface2}_ip"]}if [ -z "$ip1" ] || [ -z "$ip2" ]; then_red " Could not get IP addresses for both interfaces."return 1fiecho " Interface IPs:"echo " $iface1: $(_yellow "$ip1")"echo " $iface2: $(_yellow "$ip2")"# 測試參數local test_file_size=100 # MBlocal test_runs=3local total_speed=0local port=5000echo " This test will transfer ${test_file_size}MB between interfaces $iface1 and $iface2"_yellow " Note: This test requires IP routing to be properly configured between interfaces"# 為bash內置TCP功能準備文件描述符if _exists "bash" && [[ $(bash --version | awk 'NR==1 {print $4}' | cut -d'(' -f1) > "4.3" ]]; thenexec {net_fd}<>/dev/tcp/0.0.0.0/$portfifor ((i=1; i<=test_runs; i++)); doecho " Test $i/$test_runs: Transferring data from $iface1 to $iface2..."# 在后臺啟動接收端start_network_server $port "/dev/null"local server_pid=$!sleep 2if ! ps -p $server_pid > /dev/null; then_red " Failed to start network server. Skipping remaining tests."breakfi# 啟動發送端local start=$(date +%s.%N)cat network_test | {if _exists "socat"; thensocat - TCP4:$ip2:$portelsecat >/dev/tcp/$ip2/$portfi} >/dev/null 2>&1local end=$(date +%s.%N)# 等待傳輸完成并清理kill $server_pid 2>/dev/nullwait $server_pid 2>/dev/nulllocal duration=$(awk -v s="$start" -v e="$end" 'BEGIN{printf "%.6f", e - s}')local speed_mb=$(awk -v sz="$test_file_size" -v dur="$duration" 'BEGIN{printf "%.2f", sz / dur}')local speed_mbps=$(awk -v smb="$speed_mb" 'BEGIN{printf "%.2f", smb * 8.388608}') # MB/s to Mbpslocal speed=$(calc_bandwidth $speed_mbps)echo " Transfer Speed : $(_yellow "${speed} (${speed_mb} MB/s)")"total_speed=$(awk -v t="$total_speed" -v s="$speed_mbps" 'BEGIN{printf "%.2f", t + s}')done# 關閉bash網絡文件描述符if _exists "bash" && [[ $(bash --version | awk 'NR==1 {print $4}' | cut -d'(' -f1) > "4.3" ]]; thenexec {net_fd}>&-fiif awk -v t="$total_speed" 'BEGIN { exit !(t > 0) }'; thenlocal avg_speed_mbps=$(awk -v t="$total_speed" -v r="$test_runs" 'BEGIN{printf "%.2f", t / r}')local avg_speed=$(calc_bandwidth $avg_speed_mbps)echo " Average Speed : $(_green "${avg_speed}")"fi
}# 外部服務器帶寬測試
external_bandwidth_test() {local server=$1local port=5001local duration=10# 檢查網絡工具if ! _exists "socat" && ! ( _exists "bash" && [[ $(bash --version | awk 'NR==1 {print $4}' | cut -d'(' -f1) > "4.3" ]] ); then_red " No suitable network tools found (socat or bash 4.3+ required). Skipping test."return 1fiecho " Starting External Bandwidth Test to $server..."echo " Test will run for $duration seconds"# 創建臨時測試文件local temp_file=$(mktemp)# 為bash內置TCP功能準備文件描述符if _exists "bash" && [[ $(bash --version | awk 'NR==1 {print $4}' | cut -d'(' -f1) > "4.3" ]]; thenexec {net_fd}<>/dev/tcp/0.0.0.0/$portfi# 啟動接收端start_network_server $port "$temp_file"local server_pid=$!sleep 2if ! ps -p $server_pid > /dev/null; then_red " Failed to start network server. Skipping test."rm -f "$temp_file"return 1fi# 獲取本地IP用于綁定local local_ip=$(ip route get 1 | awk '{print $7; exit}')# 啟動發送端,限制時間(sleep $duration; pkill -P $$ cat) &local killer_pid=$!dd if=/dev/zero bs=1M 2>/dev/null | {if _exists "socat"; thensocat - TCP4:$server:$portelsecat >/dev/tcp/$server/$portfi} >/dev/null 2>&1 &transfer_pid=$!# 等待測試完成wait $killer_pid 2>/dev/nullsleep 1kill $server_pid 2>/dev/nullkill $transfer_pid 2>/dev/null# 關閉bash網絡文件描述符if _exists "bash" && [[ $(bash --version | awk 'NR==1 {print $4}' | cut -d'(' -f1) > "4.3" ]]; thenexec {net_fd}>&-fi# 計算傳輸數據量local transferred=$(du -b $temp_file | awk '{print $1}')rm -f $temp_fileif [ $transferred -eq 0 ]; then_red " No data transferred. Check connectivity to $server:$port"return 1fi# 計算吞吐量local mb_transferred=$(awk -v t="$transferred" 'BEGIN{printf "%.2f", t / 1048576}')local mbps=$(awk -v t="$transferred" -v d="$duration" 'BEGIN{printf "%.2f", (t * 8) / (1000000 * d)}')local speed=$(calc_bandwidth $mbps)echo " Test Duration : $(_blue "${duration} seconds")"echo " Data Transferred : $(_blue "$mb_transferred MB")"echo " Throughput : $(_yellow "$speed") ($(awk -v mbt="$mb_transferred" -v d="$duration" 'BEGIN{printf "%.2f", mbt / d}') MB/s)"return 0
}# 打印系統信息
print_system_info() {echo " CPU Model : $(_blue "${cname:-Not detected}")"[[ -n "$freq" ]] && freq_info="@ $freq MHz" || freq_info=""echo " CPU Cores : $(_blue "$cores cores $freq_info")"[[ -n "$ccache" ]] && echo " CPU Cache : $(_blue "$ccache")"[[ -n "$cpu_aes" ]] && echo " AES-NI : $(_green "? Enabled")" || echo " AES-NI : $(_red "? Disabled")"[[ -n "$cpu_virt" ]] && echo " VM-x/AMD-V : $(_green "? Enabled")" || echo " VM-x/AMD-V : $(_red "? Disabled")"echo " Total Disk : $(_yellow "$disk_total_size") $(_blue "($disk_used_size Used)")"echo " Total Mem : $(_yellow "$tram") $(_blue "($uram Used)")"[[ "$swap" != "0" ]] && echo " Total Swap : $(_blue "$swap ($uswap Used)")"echo " System Uptime : $(_blue "$up")"[[ -n "$load" ]] && echo " Load Average : $(_blue "$load")"echo " OS : $(_blue "$opsy")"echo " Arch : $(_blue "$arch ($lbit Bit)")"echo " Kernel : $(_blue "$kern")"[[ -n "$tcpctrl" ]] && echo " TCP CC : $(_yellow "$tcpctrl")"echo " Virtualization : $(_blue "${virt:-Not detected}")"# 網絡接口信息echo " Network Interfaces : $(_blue "${#network_interfaces[@]} available")"for iface in "${network_interfaces[@]}"; doecho " - $iface: ${iface_info["${iface}_ip"]} (${iface_info["${iface}_mac"]})"done
}# 打印結束時間
print_end_time() {end_time=$(date +%s)time=$((end_time - start_time))if [ $time -gt 60 ]; thenmin=$((time / 60))sec=$((time % 60))echo " Finished in : ${min} min ${sec} sec"elseecho " Finished in : ${time} sec"fiecho " Timestamp : $(date '+%Y-%m-%d %H:%M:%S %Z')"
}### 主執行流程 ###
start_time=$(date +%s)# 依賴檢查 (核心命令)
if ! _exists "free"; then_red "Error: 'free' command not found. Script cannot continue.\n"exit 1
fiif ! _exists "dd"; then_red "Error: 'dd' command not found. Script cannot continue.\n"exit 1
fi# 檢查是否有bc或awk用于浮點數運算
if ! _exists "bc" && ! _exists "awk"; then_red "Error: Either 'bc' or 'awk' is required for this script. Please install one of them.\n"exit 1
fi# 獲取系統信息
get_system_info
check_virt# 顯示標題
clear
echo "------------ Offline Server Performance Test with Network Benchmark ------------"
echo " Version : $(_green "v2025-08-01 (No netcat dependency)")"
echo " Usage : $(_red "./offline_network_bench.sh")"
next# 顯示系統信息
print_system_info
next# 執行CPU測試
cpu_benchmark
next# 執行內存測試
memory_benchmark
next# 執行增強磁盤測試
enhanced_io_test
next# 執行增強網絡測試
enhanced_network_test
next# 完成信息
print_end_time
next# 最終清理
rm -rf benchtest_* network_test 2>/dev/null
執行腳本
chmod +x linux_speed_ceshi.sh
./linux_speed_ceshi.sh