You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PowerShell控制台P2P聊天程序异步输入问题求助

基于Windows Form的PowerShell P2P消息客户端解决方案

核心思路

用Windows Form的异步机制处理消息接收,避免阻塞UI;通过文本框实现输入、按钮触发发送,同时复用原有网络通信逻辑,解决控制台输入暂停程序的问题。

完整实现代码

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

# 全局变量存储客户端连接
$global:clientConnection = $null

# 初始化主窗体
$mainForm = New-Object System.Windows.Forms.Form
$mainForm.Text = "P2P消息客户端"
$mainForm.Size = New-Object System.Drawing.Size(500, 400)
$mainForm.StartPosition = "CenterScreen"
$mainForm.FormBorderStyle = "FixedSingle"
$mainForm.MaximizeBox = $false

# 消息显示区域
$messageBox = New-Object System.Windows.Forms.RichTextBox
$messageBox.Location = New-Object System.Drawing.Point(10, 10)
$messageBox.Size = New-Object System.Drawing.Size(460, 280)
$messageBox.ReadOnly = $true
$messageBox.Font = New-Object System.Drawing.Font("Consolas", 10)
$mainForm.Controls.Add($messageBox)

# 输入文本框
$inputBox = New-Object System.Windows.Forms.TextBox
$inputBox.Location = New-Object System.Drawing.Point(10, 300)
$inputBox.Size = New-Object System.Drawing.Size(360, 25)
$inputBox.MaxLength = 1020
$inputBox.Font = New-Object System.Drawing.Font("Consolas", 10)
$mainForm.Controls.Add($inputBox)

# 发送按钮
$sendBtn = New-Object System.Windows.Forms.Button
$sendBtn.Location = New-Object System.Drawing.Point(380, 300)
$sendBtn.Size = New-Object System.Drawing.Size(90, 25)
$sendBtn.Text = "发送"
$sendBtn.Add_Click({
    $textToSend = $inputBox.Text.Trim()
    if (-not [string]::IsNullOrEmpty($textToSend)) {
        # 复用原发送逻辑
        [System.Byte[]]$bytes = [System.Text.Encoding]::ASCII.GetBytes($textToSend)
        $null = $global:clientConnection.Client.Send($bytes)
        # 本地显示自己发送的消息
        $messageBox.AppendText("[$env:USERNAME@$env:COMPUTERNAME] $textToSend`n")
        $inputBox.Clear()
    }
})
$mainForm.Controls.Add($sendBtn)

# 绑定回车发送
$inputBox.Add_KeyDown({
    if ($_.KeyCode -eq [System.Windows.Forms.Keys]::Enter) {
        $sendBtn.PerformClick()
    }
})

# 异步接收消息的函数
Function Start-AsyncMessageReceiver {
    param([Parameter(Mandatory=$true)]$client)
    $stream = $client.GetStream()
    $buffer = New-Object System.Byte[] 1024
    # 异步读取流,避免阻塞UI
    $stream.BeginRead($buffer, 0, $buffer.Length, {
        param($asyncResult)
        try {
            $i = $stream.EndRead($asyncResult)
            if ($i -ne 0) {
                $encodedText = New-Object System.Text.ASCIIEncoding
                $data = $encodedText.GetString($buffer, 0, $i)
                # 跨线程安全更新UI
                $mainForm.Invoke({
                    $messageBox.AppendText("[对方] $data`n")
                })
                # 持续监听下一条消息
                Start-AsyncMessageReceiver -client $client
            } else {
                $mainForm.Invoke({
                    $messageBox.AppendText("连接已断开`n")
                    $sendBtn.Enabled = $false
                })
            }
        } catch {
            $mainForm.Invoke({
                $messageBox.AppendText("接收消息出错: $_`n")
            })
        }
    }, $null)
}

# 替换为你的实际连接逻辑
# $global:clientConnection = New-Object System.Net.Sockets.TcpClient("目标IP", 端口)
# 启动异步接收
# Start-AsyncMessageReceiver -client $global:clientConnection

# 启动窗体
$mainForm.ShowDialog()

关键改进点

  • 非阻塞消息接收:用BeginRead/EndRead实现异步监听,不会卡住UI线程
  • UI线程安全:更新消息显示时使用Invoke方法,规避跨线程操作UI的异常
  • 输入体验优化:支持回车触发发送,输入框内置长度限制,发送后自动清空
  • 状态反馈:连接断开或出错时自动提示,并禁用发送按钮

集成说明

  1. 将原有网络连接逻辑替换示例中的注释部分,确保$global:clientConnection正确赋值
  2. 输入长度限制已通过文本框MaxLength属性实现,无需额外处理
  3. 若需服务端监听逻辑,可采用BeginAcceptTcpClient实现非阻塞连接

内容的提问来源于stack exchange,提问作者Dominiq

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 23:29:55