Windows 快速 ping 工具

Windows 快速 ping 工具

windows 自带的 ping 工具不能指定发包间隔,于是自己写了一个可以快速打 ping 包的工具

源码:

param(
    [Alias("t")]
    [Parameter(Mandatory=$false, Position=0)]
    [string]$Target = "www.example.com",
    
    [Alias("n")]
    [Parameter(Mandatory=$false)]
    [int]$Count = 10,
    
    [Alias("s")]
    [Parameter(Mandatory=$false)]
    [double]$IntervalSeconds = 0.2,
    
    [Alias("l")]
    [Parameter(Mandatory=$false)]
    [int]$BufferSize = 32,
    
    [Alias("w")]
    [Parameter(Mandatory=$false)]
    [int]$Timeout = 4000,
    
    [Alias("h", "?")]
    [Parameter(Mandatory=$false)]
    [switch]$Help,
    
    [Alias("c")]
    [Parameter(Mandatory=$false)]
    [switch]$Continuous,
    
    # 使用-v6参数强制IPv6
    [Alias("v6")]
    [Parameter(Mandatory=$false)]
    [switch]$ForceIPv6
)

# 显示帮助信息
function Show-Help {
    Write-Host "`n自定义Ping工具 - 毫秒级间隔控制" -ForegroundColor Cyan
    Write-Host "========================================" -ForegroundColor Cyan
    
    Write-Host "`n用途: 执行可调节间隔时间和包大小的Ping测试" -ForegroundColor Yellow
    Write-Host "`n使用方法:" -ForegroundColor Green
    Write-Host "  fastping.ps1 [目标地址] [参数]"
    Write-Host "  fastping.ps1 [参数] [目标地址]"
    
    Write-Host "`n参数说明:" -ForegroundColor Green
    Write-Host "  -t, -Target <地址>      目标IP或域名 (默认: www.example.com)"
    Write-Host "  -n, -Count <次数>       发送次数 (默认: 10)"
    Write-Host "  -s, -IntervalSeconds <秒> 间隔时间(秒) (默认: 0.2 = 200ms)"
    Write-Host "  -l, -BufferSize <字节>  包大小(字节) (默认: 32)"
    Write-Host "  -w, -Timeout <毫秒>     超时时间(毫秒) (默认: 4000)"
    Write-Host "  -c, -Continuous         连续模式,按Ctrl+C停止"
    Write-Host "  -v6, -ForceIPv6         强制使用IPv6地址"
    Write-Host "  -h, -?, -Help           显示此帮助信息"
    
    Write-Host "`n使用示例:" -ForegroundColor Green
    Write-Host "  基本使用:"
    Write-Host "    fastping.ps1 8.8.8.8"
    Write-Host "    fastping.ps1 -t google.com -n 20"
    
    Write-Host "  `n毫秒级间隔:"
    Write-Host "    fastping.ps1 192.168.1.1 -s 0.05     # 50毫秒间隔"
    Write-Host "    fastping.ps1 8.8.8.8 -s 0.01        # 10毫秒间隔"
    
    Write-Host "  `n控制包大小:"
    Write-Host "    fastping.ps1 example.com -l 64      # 64字节包"
    Write-Host "    fastping.ps1 example.com -l 1024    # 1KB大包测试"
    
    Write-Host "  `nIPv6测试:"
    Write-Host "    fastping.ps1 baidu.com -v6          # 强制使用IPv6"
    Write-Host "    fastping.ps1 ipv6.google.com -v6    # IPv6域名测试"
    Write-Host "    fastping.ps1 2001:4860:4860::8888   # 直接使用IPv6地址"
    
    Write-Host "  `n组合参数:"
    Write-Host "    fastping.ps1 8.8.8.8 -n 50 -s 0.1 -l 512 -w 2000"
    Write-Host "    fastping.ps1 google.com -c -s 0.5    # 连续ping"
    Write-Host "    fastping.ps1 baidu.com -v6 -n 20 -s 0.2"
    
    Write-Host "  `n帮助信息:"
    Write-Host "    fastping.ps1 -h"
    Write-Host "    fastping.ps1 -?"
    
    Write-Host "`n注意事项:" -ForegroundColor Magenta
    Write-Host "  * 间隔时间精度受系统限制,约10-20毫秒"
    Write-Host "  * ICMP包最大有效负载通常为1472字节(1500-20-8)"
    Write-Host "  * 连续模式中按 Ctrl+C 停止测试"
    Write-Host "  * 首次运行可能需要: Set-ExecutionPolicy RemoteSigned"
    Write-Host "  * 使用 -v6 参数时,确保系统已启用IPv6且目标支持IPv6"
    
    exit 0
}

# 如果请求帮助,显示帮助信息并退出
if ($Help) {
    Show-Help
}

# 解析目标地址的函数(保持不变)
function Resolve-TargetAddress {
    param(
        [string]$TargetName,
        [bool]$ForceIPv6
    )
    
    # 检查是否是IP地址
    $ipAddress = $null
    if ([System.Net.IPAddress]::TryParse($TargetName, [ref]$ipAddress)) {
        # 已经是IP地址
        if ($ForceIPv6 -and $ipAddress.AddressFamily -ne [System.Net.Sockets.AddressFamily]::InterNetworkV6) {
            Write-Host "错误: 目标地址 '$TargetName' 不是IPv6地址,但使用了IPv6模式" -ForegroundColor Red
            exit 1
        }
        return $ipAddress
    }
    
    # 解析域名
    Write-Host "正在解析: $TargetName ..." -ForegroundColor DarkGray
    
    try {
        $addresses = [System.Net.Dns]::GetHostAddresses($TargetName)
        
        if ($addresses.Count -eq 0) {
            Write-Host "错误: 无法解析 '$TargetName'" -ForegroundColor Red
            exit 1
        }
        
        # 根据IPv6参数筛选地址
        if ($ForceIPv6) {
            $ipv6Addresses = $addresses | Where-Object { $_.AddressFamily -eq [System.Net.Sockets.AddressFamily]::InterNetworkV6 }
            if ($ipv6Addresses.Count -eq 0) {
                Write-Host "错误: 目标 '$TargetName' 没有IPv6地址" -ForegroundColor Red
                Write-Host "可用地址:" -ForegroundColor Yellow
                $addresses | ForEach-Object { Write-Host "  $($_.ToString()) ($($_.AddressFamily))" }
                exit 1
            }
            
            # 优先选择全局IPv6地址
            $selectedAddress = $ipv6Addresses | Where-Object { 
                $_.ToString() -notmatch '^fe80:' -and $_.ToString() -notmatch '^::1$'
            } | Select-Object -First 1
            
            if (-not $selectedAddress) {
                $selectedAddress = $ipv6Addresses[0]
            }
            
            Write-Host "已选择IPv6地址: $($selectedAddress.ToString())" -ForegroundColor Cyan
            return $selectedAddress
        }
        else {
            # 默认优先选择IPv4地址
            $ipv4Addresses = $addresses | Where-Object { $_.AddressFamily -eq [System.Net.Sockets.AddressFamily]::InterNetwork }
            if ($ipv4Addresses.Count -gt 0) {
                $selectedAddress = $ipv4Addresses[0]
                Write-Host "已选择IPv4地址: $($selectedAddress.ToString())" -ForegroundColor Cyan
                return $selectedAddress
            }
            else {
                # 只有IPv6地址时使用IPv6
                Write-Host "注意: 目标 '$TargetName' 只有IPv6地址,自动使用IPv6" -ForegroundColor Yellow
                $selectedAddress = $addresses[0]
                Write-Host "已选择地址: $($selectedAddress.ToString())" -ForegroundColor Cyan
                return $selectedAddress
            }
        }
    }
    catch {
        Write-Host "错误: 解析 '$TargetName' 时出错: $_" -ForegroundColor Red
        exit 1
    }
}

# 连续模式处理
if ($Continuous) {
    $Count = [int]::MaxValue
    Write-Host "`n进入连续ping模式 (按 Ctrl+C 停止)..." -ForegroundColor Yellow
}

# 解析目标地址
$resolvedAddress = Resolve-TargetAddress -TargetName $Target -ForceIPv6 $ForceIPv6
$addressFamily = if ($resolvedAddress.AddressFamily -eq [System.Net.Sockets.AddressFamily]::InterNetworkV6) { "IPv6" } else { "IPv4" }

# 显示测试信息
Write-Host "`n自定义Ping测试开始" -ForegroundColor Cyan
Write-Host "目标: $Target ($($resolvedAddress.ToString()) - $addressFamily)" -ForegroundColor White
Write-Host "设置: $Count 次, ${IntervalSeconds}s 间隔, ${BufferSize}字节包" -ForegroundColor White
if ($ForceIPv6) {
    Write-Host "模式: IPv6强制模式已启用" -ForegroundColor Yellow
}
Write-Host "`n" + ("-" * 60) + "`n" -ForegroundColor DarkGray

# 创建Ping对象和缓冲区
$ping = New-Object System.Net.NetworkInformation.Ping
$buffer = [byte[]]::new($BufferSize)
for ($i=0; $i -lt $BufferSize; $i++) {
    $buffer[$i] = 97  # ASCII 'a'
}

# 统计变量
$successCount = 0
$totalTime = 0
$minTime = [int]::MaxValue
$maxTime = 0
$startTime = Get-Date

# 执行Ping循环
for ($i=1; $i -le $Count; $i++) {
    $timestamp = Get-Date -Format "HH:mm:ss.fff"
    Write-Host "[$timestamp] #$i" -NoNewline -ForegroundColor DarkGray
    
    if ($Continuous -and $i -eq 1) {
        Write-Host " (连续模式)" -NoNewline -ForegroundColor Yellow
    }
    
    Write-Host " 发送 ${BufferSize}字节..." -NoNewline
    
    try {
        $reply = $ping.Send($resolvedAddress, $Timeout, $buffer)
        
        if ($reply.Status -eq "Success") {
            $successCount++
            $totalTime += $reply.RoundtripTime
            
            if ($reply.RoundtripTime -lt $minTime) { $minTime = $reply.RoundtripTime }
            if ($reply.RoundtripTime -gt $maxTime) { $maxTime = $reply.RoundtripTime }
            
            # 根据延迟显示不同颜色
            $color = "Green"
            if ($reply.RoundtripTime -gt 100) { $color = "Yellow" }
            if ($reply.RoundtripTime -gt 200) { $color = "Red" }
            
            Write-Host " 回复自 $($reply.Address): 时间=$($reply.RoundtripTime)ms TTL=$($reply.Options.Ttl)" -ForegroundColor $color
        } else {
            Write-Host " 请求超时 ($($reply.Status))" -ForegroundColor Red
        }
    }
    catch [System.Net.NetworkInformation.PingException] {
        Write-Host " Ping错误: $($_.Exception.InnerException.Message)" -ForegroundColor Red
        
        # 特定于IPv6的错误处理
        if ($ForceIPv6 -and $_.Exception.InnerException.Message -match "No such host is known") {
            Write-Host "提示: 请确保IPv6已启用且目标支持IPv6" -ForegroundColor Yellow
        }
    }
    catch {
        Write-Host " 错误: $_" -ForegroundColor Red
    }
    
    # 最后一次不等待(连续模式除外)
    if ($i -ne $Count) {
        Start-Sleep -Seconds $IntervalSeconds
    }
    
    # 连续模式每10次显示一次统计
    if ($Continuous -and $i % 10 -eq 0 -and $i -gt 0) {
        $elapsed = (Get-Date) - $startTime
        Write-Host "`n[统计] 已发送: $i, 成功: $successCount, 成功率: $([math]::Round($successCount/$i*100,1))%" -ForegroundColor Cyan
        Write-Host "`n" + ("-" * 60) + "`n" -ForegroundColor DarkGray
    }
}

# 最终统计信息
$endTime = Get-Date
$duration = $endTime - $startTime

Write-Host "`n" + ("=" * 60) -ForegroundColor Cyan
Write-Host "Ping 统计信息" -ForegroundColor Cyan
Write-Host ("-" * 60) -ForegroundColor Cyan

Write-Host "目标: $Target ($($resolvedAddress.ToString()))"
Write-Host "地址类型: $addressFamily"
Write-Host "测试时间: $($duration.ToString('mm\:ss\.fff')) (开始: $($startTime.ToString('HH:mm:ss')), 结束: $($endTime.ToString('HH:mm:ss')))"
Write-Host "发送: $Count, 成功: $successCount, 丢失: $($Count - $successCount)"

if ($successCount -gt 0) {
    $lossRate = [math]::Round(($Count - $successCount) / $Count * 100, 1)
    $avgTime = [math]::Round($totalTime / $successCount, 2)
    
    Write-Host "丢包率: ${lossRate}%"
    Write-Host "往返时间(ms): 最小=${minTime}, 最大=${maxTime}, 平均=${avgTime}"
    
    # 延迟评价
    if ($avgTime -lt 30) { $rating = "优秀" }
    elseif ($avgTime -lt 100) { $rating = "良好" }
    elseif ($avgTime -lt 200) { $rating = "一般" }
    else { $rating = "较差" }
    
    $ratingColor = @{
        "优秀" = "Green"
        "良好" = "Green" 
        "一般" = "Yellow"
        "较差" = "Red"
    }
    
    Write-Host "网络质量: $rating" -ForegroundColor $ratingColor[$rating]
}

Write-Host "包大小: ${BufferSize}字节, 间隔: ${IntervalSeconds}s"
Write-Host ("=" * 60) -ForegroundColor Cyan
LICENSED UNDER CC BY-NC-SA 4.0