【问题标题】:.Net SerialPort Readline Vs DataReceived Event Handler.Net SerialPort Readline 与 DataReceived 事件处理程序
【发布时间】:2014-03-08 11:16:20
【问题描述】:

在 VB.NET 中,使用 SerialPort.ReadLine() 方法与使用 DataReceived 事件处理程序有什么区别?目前,我正在使用数据接收事件处理程序并检测行尾。问题是数据以块的形式出现,而不是 1 行句子。如果我使用 SerialPort.ReadLine() 方法,则数据包含 1 行句子。然而,使用这种方法,有 NewLine 变量来设置端口的行结束字符。 readline 方法是否只是为我处理缓冲区?无论使用何种方法,数据是否仍以块的形式出现?

方法一:

While _continue
    Try 
        Dim message As String = _serialPort.ReadLine()
        Console.WriteLine(message)
    Catch generatedExceptionName As TimeoutException
    End Try 
End While 

方法二:

Public Sub StartListener()
    Try

        _serialport = New SerialPort()
        With _serialport
            .PortName = "COM3"
            .BaudRate = 38400
            .DataBits = 8
            .Parity = Parity.None
            .StopBits = StopBits.One
            .Handshake = Handshake.None
            AddHandler .DataReceived, AddressOf DataReceivedHandler
        End With
        _serialport.Open()

    Catch ex As Exception
    End Try
End Sub

Private Shared buffer As String = ""

Private Sub DataReceivedHandler(sender As Object, e As SerialDataReceivedEventArgs)
    Try
        Dim rcv As String = _serialport.ReadExisting()
        buffer = String.Concat(buffer, rcv)

        Dim x As Integer
        Do
            x = buffer.IndexOf(vbCrLf)
            If x > -1 Then
                Console.WriteLine(buffer.Substring(0, x).Trim())
                buffer = buffer.Remove(0, x + 2)
            End If
        Loop Until x = -1
    Catch ex as Exception
    End Try
End Sub

我目前正在使用方法 2,但正在考虑切换到方法 1,因为它看起来更安全,看起来更漂亮,但有什么意义呢?谢谢

【问题讨论】:

    标签: .net vb.net serial-port


    【解决方案1】:

    您的 ReadLine() 调用是同步的,会阻塞您的代码,可能会挂起您的程序。 DataReceived 是异步的,不是。这使得它更难使用,没有免费的午餐。但重要的是,串行端口的速度可能足够慢,以至于您的整个程序对用户输入没有响应。在控制台模式程序中或使用单独的线程时通常不是问题。

    您也可以在 DataReceived 事件处理程序中调用 ReadLine(),这很荒谬。从技术上讲,这可能会导致死锁,您应该使用 ReadTimeout 属性。

    但由于您使用控制台,可能没有什么理由使用 DataReceived。

    【讨论】:

    • SO 正在接受主持人提名。如果你有时间,我想你会是一个很好的版主。
    • 目前,我们有太多的数据进入流,我们不确定 DataReceived 事件的可靠性。我们遇到了消息部分相互混淆的问题。我猜它与访问相同共享变量的异步部分有关。我认为缓冲区正在被修改,而不是按照数据进入的顺序。有什么建议吗?谢谢你
    • 当然,DataReceived 在另一个线程上运行。在你的 sn-p 中根本看不到同步,所以你确实有问题。
    • 我继续编辑方法 2 以显示更多细节,我可以使用此方法添加流控制吗?谢谢
    • 您添加的内容都无关紧要,线程同步与流控制不同。我建议使用“方法 1”,我不知道您为什么不遵循建议。一遍又一遍。
    【解决方案2】:

    使用 .NET SerialPort 实现时,您应该绝不尝试使用 DataReceived 事件和任何其他方法从串行端口读取数据。 ReadExistingReadLine 都使用相同的底层 MemoryStream。当事件中断导致您尝试读取已从流中删除的数据时,您将遇到从 ReadLine 中拉出 MemoryStream 数据的情况。

    使用一种方法或另一种方法。两者都不要使用。

    Hans Passant 关于 ReadLine 阻塞你的 UI 线程是正确的。你有两种方法:使用DataReceived 事件;或将处理SerialPort 的代码放在单独的线程上。

    使用DataReceived 事件通常更可取,因为 .NET 会自动在工作线程上运行它。不过,您会失去ReadLine 的免费赠品。如果您需要执行预读(为您提供类似 ReadLine 功能),您必须手动缓冲输入。

    【讨论】:

    • 目前,我们有太多的数据进入流,我们不确定 DataReceived 事件的可靠性。我们遇到了消息部分相互混淆的问题。我猜它与访问相同共享变量的异步部分有关。我认为缓冲区正在被修改,而不是按照数据进入的顺序。有什么建议吗?谢谢你
    • 您是否尝试通过单个串行端口进行多个并发通信?如果是这样,您将需要实现某种类型的协议,让您知道什么响应属于什么请求、响应代码的结尾以及一大堆其他事情。 SerialPort 不像 USB 连接,您可以轻松地进行单独和并发传输。如果没有,听起来你的流控制还没有实现,可能是你忽略了它。
    • 查看您提供的代码,我根本看不到任何对流控制的引用。至少,您应该实现软件流控制。最好的解决方案(如果你的电缆支持的话)是硬件流控制。
    • 我继续编辑方法 2 以显示更多细节,我可以使用 .net 添加流量控制吗?谢谢
    • 是的,你可以。您添加哪种流量控制将取决于您拥有的电缆和远程端的设备。如果电缆或远程设备不支持硬件流控制,则必须使用软件流控制。你有一行:.Handshake = Handshake.None 说不使用任何类型的流量控制。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多