|
|
本帖最后由 kedion 于 2026-5-21 19:49 编辑
iperf3一款主动式网络性能测量工具,主要用途是测量IP网络上可达的最大带宽。它能模拟并测量TCP、UDP和SCTP等主流协议的吞吐量、丢包率、抖动和重传等关键网络性能指标,由于原版iperf3是个命令行程序,并且是全英文状态,不适合普通人测试使用,所以通过deepseek使用powershell写了个简单GUI界面,方便普通人测试自己主机网络情况,由于代码是全有deepseek编写,欢迎大家反馈问题
- <font size="3">Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force
- $scriptDirectory = $PSScriptRoot
- if (-not $scriptDirectory) { $scriptDirectory = Get-Location }
- # 自动查找 iperf3.exe
- $script:iperfPath = $null
- try {
- $searchPaths = @(
- (Join-Path $scriptDirectory "iperf3.exe"),
- (Join-Path ([System.IO.Path]::GetTempPath()) "iperf3.exe")
- )
- foreach ($path in $searchPaths) {
- if (Test-Path $path) { $script:iperfPath = $path; break }
- }
- if (-not $script:iperfPath -and (Test-Path "iperf3.exe")) {
- $script:iperfPath = (Resolve-Path "iperf3.exe").Path
- }
- } catch {
- $script:iperfPath = $null
- }
- Add-Type -AssemblyName System.Windows.Forms, System.Drawing
- # 全局变量
- $script:iperfProcess = $null
- $script:running = $false
- $script:modifiedAdapters = @{}
- $script:logfilePath = ""
- $script:isAdministrator = $false
- $script:tempOutputFile = ""
- $script:lastReadPosition = 0
- $script:updateTimer = $null
- $script:monitorTimer = $null
- # ================= 主窗体 =================
- $form = New-Object System.Windows.Forms.Form
- $form.Text = "iperf3 图形界面 + 网络配置工具 (管理员模式)"
- $form.Size = New-Object System.Drawing.Size(1150, 950) # 增加高度
- $form.StartPosition = "CenterScreen"
- $form.Add_FormClosing({
- param($obj, $e)
- if ($script:running) { Stop-IperfTest }
- Restore-ModifiedNetworkConfigurations
- })
- $mainTable = New-Object System.Windows.Forms.TableLayoutPanel
- $mainTable.Dock = "Fill"
- $mainTable.ColumnCount = 2
- $mainTable.RowCount = 1
- [void]$mainTable.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Absolute, 400))) # 缩减左侧宽度
- [void]$mainTable.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::Percent, 100)))
- $form.Controls.Add($mainTable)
- # ----------------- 左侧面板 -----------------
- $leftPanel = New-Object System.Windows.Forms.Panel
- $leftPanel.Dock = "Fill"
- $leftPanel.AutoScroll = $true
- $mainTable.Controls.Add($leftPanel, 0, 0)
- $flowPanel = New-Object System.Windows.Forms.FlowLayoutPanel
- $flowPanel.Dock = "Fill"
- $flowPanel.FlowDirection = "TopDown"
- $flowPanel.AutoScroll = $true
- $flowPanel.Padding = New-Object System.Windows.Forms.Padding(10)
- $flowPanel.WrapContents = $false
- $leftPanel.Controls.Add($flowPanel)
- # ----- 1. 运行模式 -----
- $groupMode = New-Object System.Windows.Forms.GroupBox
- $groupMode.Text = "运行模式"
- $groupMode.Width = 370
- $groupMode.Height = 65
- $flowPanel.Controls.Add($groupMode)
- $radioClient = New-Object System.Windows.Forms.RadioButton
- $radioClient.Text = "客户端 (Client)"
- $radioClient.Location = New-Object System.Drawing.Point(15, 25)
- $radioClient.Size = New-Object System.Drawing.Size(130, 25)
- $radioClient.Checked = $true
- $groupMode.Controls.Add($radioClient)
- $radioServer = New-Object System.Windows.Forms.RadioButton
- $radioServer.Text = "服务器 (Server)"
- $radioServer.Location = New-Object System.Drawing.Point(160, 25)
- $radioServer.Size = New-Object System.Drawing.Size(130, 25)
- $groupMode.Controls.Add($radioServer)
- # ----- 2. 网络 IP 配置 -----
- $groupNet = New-Object System.Windows.Forms.GroupBox
- $groupNet.Text = "网络 IP 配置 (退出时恢复原始配置)"
- $groupNet.Width = 370
- $groupNet.Height = 230 # 增加高度
- $flowPanel.Controls.Add($groupNet)
- $yNet = 20
- $labelWidth = 80
- $ctrlStartX = 90
- $ctrlWidth = 170
- $lblAdapter = New-Object System.Windows.Forms.Label
- $lblAdapter.Text = "网卡适配器:"
- $lblAdapter.Location = New-Object System.Drawing.Point(10, $yNet)
- $lblAdapter.Size = New-Object System.Drawing.Size($labelWidth, 25)
- $groupNet.Controls.Add($lblAdapter)
- $comboAdapter = New-Object System.Windows.Forms.ComboBox
- $comboAdapter.DropDownStyle = "DropDownList"
- $comboAdapter.Location = New-Object System.Drawing.Point($ctrlStartX, $yNet)
- $comboAdapter.Size = New-Object System.Drawing.Size(260, 25)
- $groupNet.Controls.Add($comboAdapter)
- $yNet += 35
- $lblCurrentIP = New-Object System.Windows.Forms.Label
- $lblCurrentIP.Text = "当前IP地址:"
- $lblCurrentIP.Location = New-Object System.Drawing.Point(10, $yNet)
- $lblCurrentIP.Size = New-Object System.Drawing.Size($labelWidth, 25)
- $groupNet.Controls.Add($lblCurrentIP)
- $txtCurrentIP = New-Object System.Windows.Forms.TextBox
- $txtCurrentIP.ReadOnly = $true
- $txtCurrentIP.BackColor = "LightGray"
- $txtCurrentIP.Location = New-Object System.Drawing.Point($ctrlStartX, $yNet)
- $txtCurrentIP.Size = New-Object System.Drawing.Size(260, 23)
- $groupNet.Controls.Add($txtCurrentIP)
- $yNet += 35
- $lblNewIP = New-Object System.Windows.Forms.Label
- $lblNewIP.Text = "新IP地址:"
- $lblNewIP.Location = New-Object System.Drawing.Point(10, $yNet)
- $lblNewIP.Size = New-Object System.Drawing.Size($labelWidth, 25)
- $groupNet.Controls.Add($lblNewIP)
- $txtNewIP = New-Object System.Windows.Forms.TextBox
- $txtNewIP.Location = New-Object System.Drawing.Point($ctrlStartX, $yNet)
- $txtNewIP.Size = New-Object System.Drawing.Size($ctrlWidth, 23)
- $groupNet.Controls.Add($txtNewIP)
- $yNet += 35
- $lblSubnet = New-Object System.Windows.Forms.Label
- $lblSubnet.Text = "子网掩码:"
- $lblSubnet.Location = New-Object System.Drawing.Point(10, $yNet)
- $lblSubnet.Size = New-Object System.Drawing.Size($labelWidth, 25)
- $groupNet.Controls.Add($lblSubnet)
- $txtSubnet = New-Object System.Windows.Forms.TextBox
- $txtSubnet.Text = "255.255.255.0"
- $txtSubnet.Location = New-Object System.Drawing.Point($ctrlStartX, $yNet)
- $txtSubnet.Size = New-Object System.Drawing.Size($ctrlWidth, 23)
- $groupNet.Controls.Add($txtSubnet)
- $yNet += 35
- $btnApplyIP = New-Object System.Windows.Forms.Button
- $btnApplyIP.Text = "应用 IP 设置"
- $btnApplyIP.Location = New-Object System.Drawing.Point($ctrlStartX, $yNet)
- $btnApplyIP.Size = New-Object System.Drawing.Size(140, 35)
- $groupNet.Controls.Add($btnApplyIP)
- $yNet += 45
- $lblIPStatus = New-Object System.Windows.Forms.Label
- $lblIPStatus.Text = "就绪"
- $lblIPStatus.Location = New-Object System.Drawing.Point(10, $yNet)
- $lblIPStatus.Size = New-Object System.Drawing.Size(340, 25)
- $groupNet.Controls.Add($lblIPStatus)
- # ----- 3. iperf3 参数设置 -----
- $groupAll = New-Object System.Windows.Forms.GroupBox
- $groupAll.Text = "iperf3 测试参数设置"
- $groupAll.Width = 370
- $groupAll.Height = 420 # 增加高度
- $flowPanel.Controls.Add($groupAll)
- $y = 20
- $lblServer = New-Object System.Windows.Forms.Label
- $lblServer.Text = "服务器地址:"
- $lblServer.Location = New-Object System.Drawing.Point(10, $y)
- $lblServer.Size = New-Object System.Drawing.Size(75, 25)
- $groupAll.Controls.Add($lblServer)
- $txtServer = New-Object System.Windows.Forms.TextBox
- $txtServer.Text = "127.0.0.1"
- $txtServer.Location = New-Object System.Drawing.Point(90, $y)
- $txtServer.Size = New-Object System.Drawing.Size(260, 23)
- $groupAll.Controls.Add($txtServer)
- $y += 35
- $lblPort = New-Object System.Windows.Forms.Label
- $lblPort.Text = "端口:"
- $lblPort.Location = New-Object System.Drawing.Point(10, $y)
- $lblPort.Size = New-Object System.Drawing.Size(45, 25)
- $groupAll.Controls.Add($lblPort)
- $txtPort = New-Object System.Windows.Forms.TextBox
- $txtPort.Text = "5201"
- $txtPort.Location = New-Object System.Drawing.Point(55, $y)
- $txtPort.Size = New-Object System.Drawing.Size(70, 23)
- $groupAll.Controls.Add($txtPort)
- $lblProto = New-Object System.Windows.Forms.Label
- $lblProto.Text = "协议:"
- $lblProto.Location = New-Object System.Drawing.Point(135, $y)
- $lblProto.Size = New-Object System.Drawing.Size(45, 25)
- $groupAll.Controls.Add($lblProto)
- $comboProto = New-Object System.Windows.Forms.ComboBox
- $comboProto.DropDownStyle = "DropDownList"
- [void]$comboProto.Items.AddRange(@("tcp", "udp", "sctp"))
- $comboProto.SelectedIndex = 0
- $comboProto.Location = New-Object System.Drawing.Point(180, $y)
- $comboProto.Size = New-Object System.Drawing.Size(170, 25)
- $groupAll.Controls.Add($comboProto)
- $y += 35
- $lblDuration = New-Object System.Windows.Forms.Label
- $lblDuration.Text = "测试时长:"
- $lblDuration.Location = New-Object System.Drawing.Point(10, $y)
- $lblDuration.Size = New-Object System.Drawing.Size(75, 25)
- $groupAll.Controls.Add($lblDuration)
- $numHour = New-Object System.Windows.Forms.NumericUpDown
- $numHour.Location = New-Object System.Drawing.Point(85, $y)
- $numHour.Size = New-Object System.Drawing.Size(45, 23)
- $numHour.Minimum = 0
- $numHour.Maximum = 23
- $numHour.Value = 0
- $groupAll.Controls.Add($numHour)
- $lblHour = New-Object System.Windows.Forms.Label
- $lblHour.Text = "时"
- $lblHour.Location = New-Object System.Drawing.Point(135, $y)
- $lblHour.Size = New-Object System.Drawing.Size(25, 25)
- $groupAll.Controls.Add($lblHour)
- $numMinute = New-Object System.Windows.Forms.NumericUpDown
- $numMinute.Location = New-Object System.Drawing.Point(160, $y)
- $numMinute.Size = New-Object System.Drawing.Size(45, 23)
- $numMinute.Minimum = 0
- $numMinute.Maximum = 59
- $numMinute.Value = 0
- $groupAll.Controls.Add($numMinute)
- $lblMinute = New-Object System.Windows.Forms.Label
- $lblMinute.Text = "分"
- $lblMinute.Location = New-Object System.Drawing.Point(210, $y)
- $lblMinute.Size = New-Object System.Drawing.Size(25, 25)
- $groupAll.Controls.Add($lblMinute)
- $numSecond = New-Object System.Windows.Forms.NumericUpDown
- $numSecond.Location = New-Object System.Drawing.Point(235, $y)
- $numSecond.Size = New-Object System.Drawing.Size(45, 23)
- $numSecond.Minimum = 0
- $numSecond.Maximum = 59
- $numSecond.Value = 10
- $groupAll.Controls.Add($numSecond)
- $lblSecond = New-Object System.Windows.Forms.Label
- $lblSecond.Text = "秒"
- $lblSecond.Location = New-Object System.Drawing.Point(285, $y)
- $lblSecond.Size = New-Object System.Drawing.Size(25, 25)
- $groupAll.Controls.Add($lblSecond)
- $y += 35
- $lblParallel = New-Object System.Windows.Forms.Label
- $lblParallel.Text = "并行流数:"
- $lblParallel.Location = New-Object System.Drawing.Point(10, $y)
- $lblParallel.Size = New-Object System.Drawing.Size(75, 25)
- $groupAll.Controls.Add($lblParallel)
- $txtParallel = New-Object System.Windows.Forms.TextBox
- $txtParallel.Text = "1"
- $txtParallel.Location = New-Object System.Drawing.Point(85, $y)
- $txtParallel.Size = New-Object System.Drawing.Size(55, 23)
- $groupAll.Controls.Add($txtParallel)
- $y += 35
- $lblUdpBw = New-Object System.Windows.Forms.Label
- $lblUdpBw.Text = "UDP带宽(Mbps):"
- $lblUdpBw.Location = New-Object System.Drawing.Point(10, $y)
- $lblUdpBw.Size = New-Object System.Drawing.Size(110, 25)
- $groupAll.Controls.Add($lblUdpBw)
- $txtUdpBw = New-Object System.Windows.Forms.TextBox
- $txtUdpBw.Text = "100"
- $txtUdpBw.Location = New-Object System.Drawing.Point(120, $y)
- $txtUdpBw.Size = New-Object System.Drawing.Size(70, 23)
- $groupAll.Controls.Add($txtUdpBw)
- $y += 35
- # ----- 测试模式选项 -----
- $groupTestMode = New-Object System.Windows.Forms.GroupBox
- $groupTestMode.Text = "测试模式 (仅客户端)"
- $groupTestMode.Location = New-Object System.Drawing.Point(10, $y)
- $groupTestMode.Size = New-Object System.Drawing.Size(350, 125)
- $groupAll.Controls.Add($groupTestMode)
- $radioDefault = New-Object System.Windows.Forms.RadioButton
- $radioDefault.Text = "默认模式(客户端发送)"
- $radioDefault.Location = New-Object System.Drawing.Point(10, 25)
- $radioDefault.Size = New-Object System.Drawing.Size(200, 25)
- $radioDefault.Checked = $true
- $groupTestMode.Controls.Add($radioDefault)
- $radioReverse = New-Object System.Windows.Forms.RadioButton
- $radioReverse.Text = "反向测试 (服务器发送)"
- $radioReverse.Location = New-Object System.Drawing.Point(10, 50)
- $radioReverse.Size = New-Object System.Drawing.Size(200, 25)
- $groupTestMode.Controls.Add($radioReverse)
- $radioBidir = New-Object System.Windows.Forms.RadioButton
- $radioBidir.Text = "独立双向测试 (先客户端后服务器)"
- $radioBidir.Location = New-Object System.Drawing.Point(10, 75)
- $radioBidir.Size = New-Object System.Drawing.Size(300, 25)
- $groupTestMode.Controls.Add($radioBidir)
- $radioDualtest = New-Object System.Windows.Forms.RadioButton
- $radioDualtest.Text = "同时双向测试 (客户端与服务器同时)"
- $radioDualtest.Location = New-Object System.Drawing.Point(10, 100)
- $radioDualtest.Size = New-Object System.Drawing.Size(300, 25)
- $groupTestMode.Controls.Add($radioDualtest)
- $y += 135
- # ----- 日志文件选项 -----
- $chkLogfile = New-Object System.Windows.Forms.CheckBox
- $chkLogfile.Text = "保存日志到文件"
- $chkLogfile.Location = New-Object System.Drawing.Point(10, $y)
- $chkLogfile.Size = New-Object System.Drawing.Size(110, 25)
- $groupAll.Controls.Add($chkLogfile)
- $txtLogfilePath = New-Object System.Windows.Forms.TextBox
- $txtLogfilePath.ReadOnly = $true
- $txtLogfilePath.BackColor = "LightGray"
- $txtLogfilePath.Location = New-Object System.Drawing.Point(120, $y)
- $txtLogfilePath.Size = New-Object System.Drawing.Size(230, 23)
- $txtLogfilePath.Text = "未选择"
- $groupAll.Controls.Add($txtLogfilePath)
- $y += 35
- $btnStart = New-Object System.Windows.Forms.Button
- $btnStart.Text = "启动测试"
- $btnStart.Location = New-Object System.Drawing.Point(15, $y)
- $btnStart.Size = New-Object System.Drawing.Size(85, 35)
- $groupAll.Controls.Add($btnStart)
- $btnStop = New-Object System.Windows.Forms.Button
- $btnStop.Text = "停止"
- $btnStop.Enabled = $false
- $btnStop.Location = New-Object System.Drawing.Point(115, $y)
- $btnStop.Size = New-Object System.Drawing.Size(85, 35)
- $groupAll.Controls.Add($btnStop)
- $btnClear = New-Object System.Windows.Forms.Button
- $btnClear.Text = "清空输出"
- $btnClear.Location = New-Object System.Drawing.Point(215, $y)
- $btnClear.Size = New-Object System.Drawing.Size(85, 35)
- $groupAll.Controls.Add($btnClear)
- # ================= 右侧输出面板 =================
- $rightPanel = New-Object System.Windows.Forms.Panel
- $rightPanel.Dock = "Fill"
- $mainTable.Controls.Add($rightPanel, 1, 0)
- $txtOutput = New-Object System.Windows.Forms.RichTextBox
- $txtOutput.Dock = "Fill"
- $txtOutput.ReadOnly = $true
- $txtOutput.BackColor = "Black"
- $txtOutput.ForeColor = "LightGreen"
- $txtOutput.Font = New-Object System.Drawing.Font("Consolas", 10)
- $rightPanel.Controls.Add($txtOutput)
- # ================= 功能函数 =================
- function Write-OutputLog {
- param([string]$text)
- if ([string]::IsNullOrEmpty($text)) { return }
- $txtOutput.AppendText($text + "`r`n")
- $txtOutput.ScrollToCaret()
- }
- # ---------- 网络配置函数 ----------
- function Backup-SingleNetworkConfig {
- param([int]$ifIndex, [string]$ifAlias)
- if ($script:modifiedAdapters.ContainsKey($ifIndex)) { return }
- $ipInterface = Get-NetIPInterface -InterfaceIndex $ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue
- $dhcpEnabled = $ipInterface.Dhcp -eq "Enabled"
- $ipAddresses = @()
- if (-not $dhcpEnabled) {
- $ipAddresses = Get-NetIPAddress -InterfaceIndex $ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue
- }
- $config = @{
- InterfaceAlias = $ifAlias
- DHCP = $dhcpEnabled
- IPAddresses = @()
- }
- foreach ($ip in $ipAddresses) {
- $config.IPAddresses += @{
- IPAddress = $ip.IPAddress
- PrefixLength = $ip.PrefixLength
- }
- }
- $script:modifiedAdapters[$ifIndex] = $config
- if ($dhcpEnabled) {
- Write-OutputLog "已备份 $ifAlias 的原始配置 (DHCP 自动获取)"
- } else {
- $ipStr = if ($config.IPAddresses.Count -gt 0) { $config.IPAddresses[0].IPAddress } else { "无" }
- Write-OutputLog "已备份 $ifAlias 的原始配置 (静态 IP: $ipStr)"
- }
- }
- function Restore-ModifiedNetworkConfigurations {
- if ($script:modifiedAdapters.Count -eq 0) { return }
- Write-OutputLog "正在恢复被修改的网卡到原始配置..."
- foreach ($ifIndex in $script:modifiedAdapters.Keys) {
- $config = $script:modifiedAdapters[$ifIndex]
- $adapter = Get-NetAdapter -InterfaceIndex $ifIndex -ErrorAction SilentlyContinue
- if (-not $adapter) { continue }
- try {
- Get-NetIPAddress -InterfaceIndex $ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue | ForEach-Object {
- Remove-NetIPAddress -InterfaceIndex $ifIndex -IPAddress $_.IPAddress -Confirm:$false -ErrorAction SilentlyContinue
- }
- if ($config.DHCP) {
- Set-NetIPInterface -InterfaceIndex $ifIndex -Dhcp Enabled -ErrorAction SilentlyContinue
- ipconfig /renew $adapter.Name | Out-Null
- } else {
- Set-NetIPInterface -InterfaceIndex $ifIndex -Dhcp Disabled -ErrorAction SilentlyContinue
- foreach ($ipObj in $config.IPAddresses) {
- New-NetIPAddress -InterfaceIndex $ifIndex -IPAddress $ipObj.IPAddress -PrefixLength $ipObj.PrefixLength -ErrorAction SilentlyContinue | Out-Null
- }
- }
- } catch {
- Write-OutputLog "恢复 $($config.InterfaceAlias) 失败: $($_.Exception.Message)"
- }
- }
- $script:modifiedAdapters.Clear()
- Update-CurrentIPDisplay
- Write-OutputLog "网络配置恢复完成。"
- }
- function Initialize-NetworkAdapters {
- try {
- $adapters = Get-NetAdapter | Where-Object {$_.Status -eq 'Up'}
- $comboAdapter.Items.Clear()
- foreach ($adapter in $adapters) {
- [void]$comboAdapter.Items.Add($adapter.InterfaceAlias)
- }
- if ($comboAdapter.Items.Count -gt 0) {
- [void]($comboAdapter.SelectedIndex = 0)
- Update-CurrentIPDisplay
- }
- } catch {
- Write-OutputLog "加载网卡列表失败: $($_.Exception.Message)"
- }
- }
- function Update-CurrentIPDisplay {
- $selectedAdapter = $comboAdapter.SelectedItem
- if (-not $selectedAdapter) { return }
- $adapter = Get-NetAdapter -InterfaceAlias $selectedAdapter -ErrorAction SilentlyContinue
- if ($adapter) {
- $ipAddress = Get-NetIPAddress -InterfaceIndex $adapter.InterfaceIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue | Select-Object -First 1
- $ipInterface = Get-NetIPInterface -InterfaceIndex $adapter.InterfaceIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue
- $dhcpEnabled = $ipInterface.Dhcp -eq "Enabled"
- if ($ipAddress) {
- $txtCurrentIP.Text = if ($dhcpEnabled) { "$($ipAddress.IPAddress) (DHCP)" } else { "$($ipAddress.IPAddress) (静态)" }
- } else {
- $txtCurrentIP.Text = if ($dhcpEnabled) { "未配置IPv4 (DHCP模式)" } else { "未配置IPv4 (静态模式)" }
- }
- } else {
- $txtCurrentIP.Text = "未知"
- }
- }
- function Get-GatewayFromIP {
- param([string]$ipAddress)
- if (-not $ipAddress) { return $null }
- $parts = $ipAddress -split '\.'
- if ($parts.Count -ne 4) { return $null }
- $parts[3] = "1"
- return $parts -join '.'
- }
- function Set-NetworkIP {
- $selectedAdapter = $comboAdapter.SelectedItem
- $newIP = $txtNewIP.Text.Trim()
- $subnetMask = $txtSubnet.Text.Trim()
-
- if (-not $selectedAdapter) { $lblIPStatus.Text = "请选择网卡"; $lblIPStatus.ForeColor = "Red"; return }
- if (-not $newIP) { $lblIPStatus.Text = "请填写新IP地址"; $lblIPStatus.ForeColor = "Red"; return }
- if ($newIP -notmatch '^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$') { $lblIPStatus.Text = "IP地址格式不正确"; $lblIPStatus.ForeColor = "Red"; return }
- if ($subnetMask -notmatch '^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$') { $lblIPStatus.Text = "子网掩码格式不正确"; $lblIPStatus.ForeColor = "Red"; return }
-
- $adapter = Get-NetAdapter -InterfaceAlias $selectedAdapter -ErrorAction SilentlyContinue
- if (-not $adapter) { $lblIPStatus.Text = "网卡不存在"; $lblIPStatus.ForeColor = "Red"; return }
- $ifIndex = $adapter.InterfaceIndex
- $ifAlias = $adapter.InterfaceAlias
- try {
- Backup-SingleNetworkConfig -ifIndex $ifIndex -ifAlias $ifAlias
- $lblIPStatus.Text = "正在修改IP,请稍候..."
- $lblIPStatus.ForeColor = "Blue"
- Set-NetIPInterface -InterfaceIndex $ifIndex -Dhcp Disabled -ErrorAction SilentlyContinue
- Get-NetIPAddress -InterfaceIndex $ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue | ForEach-Object {
- Remove-NetIPAddress -InterfaceIndex $ifIndex -IPAddress $_.IPAddress -Confirm:$false -ErrorAction SilentlyContinue
- }
- $prefixLength = ConvertTo-PrefixLength $subnetMask
- New-NetIPAddress -InterfaceIndex $ifIndex -IPAddress $newIP -PrefixLength $prefixLength -ErrorAction Stop | Out-Null
- $lblIPStatus.Text = "成功:IP已改为 $newIP,退出时将恢复原始配置"
- $lblIPStatus.ForeColor = "Green"
- Write-OutputLog "已修改网卡 $selectedAdapter 的IP为 $newIP,掩码 $subnetMask"
- Update-CurrentIPDisplay
- if ($radioClient.Checked) {
- $gatewayIP = Get-GatewayFromIP $newIP
- if ($gatewayIP) {
- $txtServer.Text = $gatewayIP
- Write-OutputLog "客户端模式:已自动将服务器地址设为 $gatewayIP"
- }
- }
- } catch {
- $lblIPStatus.Text = "修改失败:$($_.Exception.Message)"
- $lblIPStatus.ForeColor = "Red"
- }
- }
- function ConvertTo-PrefixLength {
- param([string]$mask)
- if (-not $mask) { return 24 }
- $bits = $mask.Split('.') | ForEach-Object { [convert]::ToString($_, 2).PadLeft(8,'0') }
- $binary = ($bits -join '')
- return ($binary -replace '0', '').Length
- }
- # ---------- iperf3 参数处理 ----------
- function Update-UIState {
- $isClient = $radioClient.Checked
- $txtServer.Enabled = $isClient
- $numHour.Enabled = $isClient
- $numMinute.Enabled = $isClient
- $numSecond.Enabled = $isClient
- $txtParallel.Enabled = $isClient
- $groupTestMode.Enabled = $isClient
- $chkLogfile.Enabled = $isClient
- $txtLogfilePath.Enabled = $isClient
- $txtUdpBw.Enabled = $isClient -and ($comboProto.SelectedItem -eq "udp") -and ($comboProto.SelectedItem -ne "sctp")
- }
- function Get-TotalSeconds {
- $hours = [int]$numHour.Value
- $minutes = [int]$numMinute.Value
- $seconds = [int]$numSecond.Value
- $total = $hours * 3600 + $minutes * 60 + $seconds
- if ($total -eq 0) { $total = 1 }
- return $total
- }
- function Get-CommandLineArguments {
- $isClient = $radioClient.Checked
- $argsList = @()
- if ($isClient) {
- $serverAddr = $txtServer.Text.Trim()
- if (-not $serverAddr) { Write-OutputLog "错误:客户端模式需要指定服务器地址。"; return @() }
- $argsList += "-c"
- $argsList += $serverAddr
- $duration = Get-TotalSeconds
- $argsList += "-t"; $argsList += $duration
- if ($txtParallel.Text -and $txtParallel.Text -ne "1") { $argsList += "-P"; $argsList += $txtParallel.Text }
- if ($radioReverse.Checked) { $argsList += "-R" }
- elseif ($radioBidir.Checked) { $argsList += "--bidir" }
- elseif ($radioDualtest.Checked) { $argsList += "-d" }
- $argsList += "--forceflush"
- } else {
- $argsList += "-s"
- }
- if ($txtPort.Text) { $argsList += "-p"; $argsList += $txtPort.Text }
- $protocol = $comboProto.SelectedItem
- if ($protocol -eq "udp") { $argsList += "-u" }
- elseif ($protocol -eq "sctp") { $argsList += "--sctp" }
- if ($isClient -and $protocol -eq "udp" -and $txtUdpBw.Text -match '^\d+$') {
- $argsList += "-b"; $argsList += "$($txtUdpBw.Text)M"
- }
- if ($isClient -and $chkLogfile.Checked -and $script:logfilePath -ne "") {
- $argsList += "--logfile"; $argsList += $script:logfilePath
- }
- return $argsList
- }
- # ================= 文件重定向 + 定时器方案 =================
- function Start-IperfTest {
- if (-not $script:iperfPath) {
- Write-OutputLog "错误:找不到 iperf3.exe,无法启动测试。"
- return
- }
- $argsList = Get-CommandLineArguments
- if ($argsList.Count -eq 0) { return }
- Write-OutputLog ">>> 执行命令: $script:iperfPath $argsList"
- $script:tempOutputFile = [System.IO.Path]::GetTempFileName()
- $script:lastReadPosition = 0
- $cmdArgs = "/c `"`"$script:iperfPath`" $($argsList -join ' ') > `"$script:tempOutputFile`" 2>&1`""
- $psi = New-Object System.Diagnostics.ProcessStartInfo
- $psi.FileName = "cmd.exe"
- $psi.Arguments = $cmdArgs
- $psi.UseShellExecute = $false
- $psi.CreateNoWindow = $true
- $script:iperfProcess = New-Object System.Diagnostics.Process
- $script:iperfProcess.StartInfo = $psi
- try {
- [void]$script:iperfProcess.Start()
- Write-OutputLog "iperf3 进程已启动,正在接收数据..."
- } catch {
- Write-OutputLog "启动 iperf3 失败: $($_.Exception.Message)"
- return
- }
- $script:running = $true
- $btnStart.Enabled = $false
- $btnStop.Enabled = $true
- $script:updateTimer = New-Object System.Windows.Forms.Timer
- $script:updateTimer.Interval = 100
- $script:updateTimer.Add_Tick({
- if (-not $script:tempOutputFile -or -not (Test-Path $script:tempOutputFile)) { return }
- try {
- $fs = [System.IO.File]::Open($script:tempOutputFile, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::ReadWrite)
- $fs.Seek($script:lastReadPosition, [System.IO.SeekOrigin]::Begin) | Out-Null
- $reader = New-Object System.IO.StreamReader($fs, [System.Text.Encoding]::UTF8)
- while ($true) {
- $line = $reader.ReadLine()
- if ($null -eq $line) { break }
- Write-OutputLog $line
- }
- $script:lastReadPosition = $fs.Position
- $reader.Close()
- $fs.Close()
- } catch {}
- })
- $script:updateTimer.Start()
- $script:monitorTimer = New-Object System.Windows.Forms.Timer
- $script:monitorTimer.Interval = 500
- $script:monitorTimer.Add_Tick({
- if ($script:iperfProcess -and $script:iperfProcess.HasExited) {
- if ($script:updateTimer) { $script:updateTimer.Stop(); $script:updateTimer.Dispose(); $script:updateTimer = $null }
- if ($script:monitorTimer) { $script:monitorTimer.Stop(); $script:monitorTimer.Dispose(); $script:monitorTimer = $null }
- if ($script:tempOutputFile -and (Test-Path $script:tempOutputFile)) {
- try {
- $fs = [System.IO.File]::Open($script:tempOutputFile, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::ReadWrite)
- $fs.Seek($script:lastReadPosition, [System.IO.SeekOrigin]::Begin) | Out-Null
- $reader = New-Object System.IO.StreamReader($fs, [System.Text.Encoding]::UTF8)
- while ($true) {
- $line = $reader.ReadLine()
- if ($null -eq $line) { break }
- Write-OutputLog $line
- }
- $reader.Close()
- $fs.Close()
- } catch {}
- }
- $exitCode = $script:iperfProcess.ExitCode
- Write-OutputLog "--- 测试结束,退出代码 $exitCode ---"
- Reset-TestState
- }
- })
- $script:monitorTimer.Start()
- }
- function Stop-IperfTest {
- if ($script:iperfProcess -and -not $script:iperfProcess.HasExited) {
- Write-OutputLog "正在终止 iperf 进程..."
- try {
- $script:iperfProcess.Kill()
- $script:iperfProcess.WaitForExit(2000)
- } catch {}
- }
- Reset-TestState
- Write-OutputLog "已终止。"
- }
- function Reset-TestState {
- $script:running = $false
- $btnStart.Enabled = $true
- $btnStop.Enabled = $false
- if ($script:updateTimer) { $script:updateTimer.Stop(); $script:updateTimer.Dispose(); $script:updateTimer = $null }
- if ($script:monitorTimer) { $script:monitorTimer.Stop(); $script:monitorTimer.Dispose(); $script:monitorTimer = $null }
- if ($script:iperfProcess) { $script:iperfProcess.Dispose(); $script:iperfProcess = $null }
- if ($script:tempOutputFile -and (Test-Path $script:tempOutputFile)) {
- Remove-Item $script:tempOutputFile -Force -ErrorAction SilentlyContinue
- }
- $script:tempOutputFile = ""
- $script:lastReadPosition = 0
- }
- function Clear-OutputLog {
- $txtOutput.Clear()
- }
- # ---------- 日志文件选择 ----------
- $script:logfileSelectionInProgress = $false
- function Invoke-LogfileSelection {
- if ($script:logfileSelectionInProgress) { return }
- $script:logfileSelectionInProgress = $true
- try {
- if ($chkLogfile.Checked) {
- $saveFileDialog = New-Object System.Windows.Forms.SaveFileDialog
- $saveFileDialog.Title = "选择日志文件保存位置"
- $saveFileDialog.Filter = "文本文件 (*.txt)|*.txt|所有文件 (*.*)|*.*"
- $saveFileDialog.DefaultExt = "txt"
- if ($script:logfilePath) {
- $saveFileDialog.FileName = [System.IO.Path]::GetFileName($script:logfilePath)
- $saveFileDialog.InitialDirectory = [System.IO.Path]::GetDirectoryName($script:logfilePath)
- } else {
- $saveFileDialog.InitialDirectory = $scriptDirectory
- $saveFileDialog.FileName = "iperf3_log.txt"
- }
- if ($saveFileDialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) {
- $script:logfilePath = $saveFileDialog.FileName
- $txtLogfilePath.Text = $script:logfilePath
- Write-OutputLog "日志将保存到: $script:logfilePath"
- } else {
- [void]($chkLogfile.Checked = $false)
- $txtLogfilePath.Text = "未选择"
- }
- } else {
- $script:logfilePath = ""
- $txtLogfilePath.Text = "未选择"
- }
- } finally {
- $script:logfileSelectionInProgress = $false
- }
- }
- # ================= 事件绑定 =================
- $btnStart.Add_Click({ Start-IperfTest })
- $btnStop.Add_Click({ Stop-IperfTest })
- $btnClear.Add_Click({ Clear-OutputLog })
- $radioClient.Add_CheckedChanged({ Update-UIState })
- $radioServer.Add_CheckedChanged({ Update-UIState })
- $comboProto.Add_SelectedIndexChanged({ Update-UIState })
- $comboAdapter.Add_SelectedIndexChanged({ Update-CurrentIPDisplay })
- $btnApplyIP.Add_Click({ Set-NetworkIP })
- $chkLogfile.Add_CheckedChanged({ Invoke-LogfileSelection })
- # ================= 权限检查 =================
- $script:isAdministrator = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
- if (-not $script:isAdministrator) {
- Write-OutputLog "警告:未以管理员身份运行,IP 设置功能被禁用。"
- $lblIPStatus.Text = "需要管理员权限"
- $lblIPStatus.ForeColor = "Red"
- $btnApplyIP.Enabled = $false
- $txtNewIP.Enabled = $false
- $txtSubnet.Enabled = $false
- } else {
- $lblIPStatus.Text = "就绪"
- }
- # ================= 初始化 =================
- Initialize-NetworkAdapters
- Update-UIState
- if ($script:iperfPath) {
- Write-OutputLog "欢迎使用 iperf3 图形界面工具。"
- Write-OutputLog "iperf3.exe 路径: $script:iperfPath"
- } else {
- Write-OutputLog "警告:未找到 iperf3.exe!请将 iperf3.exe 放置在脚本目录后重启程序。"
- $btnStart.Enabled = $false
- }
- try {
- $form.ShowDialog() | Out-Null
- } catch {
- [System.Windows.Forms.MessageBox]::Show("运行时异常: $($_.Exception.Message)", "错误", "OK", "Error")
- } finally {
- if ($script:updateTimer) { $script:updateTimer.Stop(); $script:updateTimer.Dispose() }
- if ($script:monitorTimer) { $script:monitorTimer.Stop(); $script:monitorTimer.Dispose() }
- if ($script:iperfProcess) {
- try { $script:iperfProcess.Kill() } catch {}
- $script:iperfProcess.Dispose()
- }
- if ($script:tempOutputFile -and (Test-Path $script:tempOutputFile)) {
- Remove-Item $script:tempOutputFile -Force -ErrorAction SilentlyContinue
- }
- Restore-ModifiedNetworkConfigurations
- }</font>
复制代码 使用方法,保存代码为ps1,右键使用powershell运行,此时无法正常以管理员权限运行,无法更改ip地址,如果需要管理员运行,可以下载附件文件放入iperf3的相同目录下运行
iperf3开源地址:https://github.com/esnet/iperf
|
|