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

VB.NET重定向Tshark捕获命令输出时StreamReader.ReadLine阻塞问题

解决VB.NET中Tshark实时抓包输出重定向阻塞问题

我来帮你分析下这个问题的根源,再给你一套可行的解决方案:

问题诊断

你的第二条命令之所以会阻塞,核心原因在于Tshark的输出缓冲机制:

  • 第一条命令输出的字段多(帧号、IP地址等),每个数据包的输出内容足够长,很快就会填满Tshark的输出缓冲区,触发内容刷新,所以ReadLine()能正常读到换行符。
  • 第二条命令只输出dns.qry.name,内容极短,Tshark默认使用块缓冲(攒够缓冲区才会输出),不会立刻把单条DNS记录刷到输出流里,导致ReadLine()一直等待换行符,最终阻塞。

另外,你原代码还有一个隐患:先读完标准输出再读标准错误,一旦Tshark往错误输出写内容并填满缓冲区,整个进程会卡住,反过来也会影响标准输出的读取。

解决方案

1. 修改Tshark命令,强制行缓冲

给第二条命令加上-l参数,这个参数会强制Tshark使用行缓冲,每捕获到一个数据包就立刻输出一行,不会攒缓冲区:

-i 10 -l -T fields -e dns.qry.name src port 53

2. 改用异步事件读取输出,避免阻塞

放弃同步的StreamReader.ReadLine()方式,改用Process的OutputDataReceived和ErrorDataReceived异步事件,同时处理标准输出和错误输出,彻底解决阻塞问题。

修改后的完整代码:

Public Class Form1
    Dim output As String = ""
    Dim oProcess As New Process()

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Try
            ' 加入-l参数强制行缓冲
            Dim oStartInfo As New ProcessStartInfo("C:\Program Files\Wireshark\tshark.exe", "-i 10 -l -T fields -e dns.qry.name src port 53")
            oStartInfo.UseShellExecute = False
            oStartInfo.RedirectStandardOutput = True
            oStartInfo.RedirectStandardError = True
            oStartInfo.CreateNoWindow = True
            oStartInfo.WindowStyle = ProcessWindowStyle.Hidden

            ' 绑定输出/错误事件处理程序
            AddHandler oProcess.OutputDataReceived, AddressOf Process_OutputDataReceived
            AddHandler oProcess.ErrorDataReceived, AddressOf Process_ErrorDataReceived

            oProcess.StartInfo = oStartInfo
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try

        BackgroundWorker1.RunWorkerAsync()
        Button1.Enabled = False
        Button2.Enabled = True
    End Sub

    Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        Try
            oProcess.Start()
            ' 启动异步读取
            oProcess.BeginOutputReadLine()
            oProcess.BeginErrorReadLine()
            ' 等待进程结束(直到手动停止)
            oProcess.WaitForExit()
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub

    ' 处理标准输出
    Private Sub Process_OutputDataReceived(sender As Object, e As DataReceivedEventArgs)
        If Not String.IsNullOrEmpty(e.Data) Then
            ' 跨线程更新UI需要Invoke确保线程安全
            Me.Invoke(Sub()
                          output &= e.Data & vbNewLine
                          TextBox1.Text = output
                          TextBox1.Select(TextBox1.TextLength, 0)
                      End Sub)
        End If
    End Sub

    ' 处理标准错误
    Private Sub Process_ErrorDataReceived(sender As Object, e As DataReceivedEventArgs)
        If Not String.IsNullOrEmpty(e.Data) Then
            Me.Invoke(Sub()
                          output &= "[ERROR] " & e.Data & vbNewLine
                          TextBox1.Text = output
                          TextBox1.Select(TextBox1.TextLength, 0)
                      End Sub)
        End If
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        ' 停止并清理进程
        If oProcess IsNot Nothing AndAlso Not oProcess.HasExited Then
            oProcess.Kill()
            oProcess.Dispose()
            oProcess = New Process()
        End If
        Button1.Enabled = True
        Button2.Enabled = False
        output = ""
        TextBox1.Text = ""
    End Sub

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    End Sub
End Class

代码改进点说明

  • 移除了原代码中不必要的Thread.Sleep(2000),避免无意义的延迟。
  • 用异步事件替代同步读取,彻底解决输出/错误缓冲区阻塞的问题。
  • 跨线程更新UI时使用Invoke,避免WinForm的线程安全报错。
  • 停止按钮中主动Kill并释放进程资源,避免Tshark后台残留。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:30:22