.Net SerialPort Readline 与 DataReceived 事件处理程序

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21688818/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 12:38:43  来源:igfitidea点击:

.Net SerialPort Readline Vs DataReceived Event Handler

.netvb.netserial-port

提问by wayofthefuture

In VB.NET, what is the difference between using the SerialPort.ReadLine() method versus using the DataReceived event handler? Currently, I'm using the data received event handler and detecting the line endings. The problem is the data is coming in chunks and not 1 line sentences. If I use SerialPort.ReadLine() method, the data comes in 1 line sentences. Using this method, however, has the NewLine variable to set the line ending character for the port. Is the readline method just handling the buffer for me? Does the data still come in chunks regardless of the method used?

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

Method 1:

方法一:

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

Method 2:

方法二:

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

I am currently using Method 2, but was thinking about switching to Method 1 because it seems safer and looks prettier you know, but what's the point? Thanks

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

回答by Hans Passant

Your ReadLine() call is synchronous and blocks your code, potentially hanging your program. DataReceived is asynchronous and doesn't. Which makes it harder to use, there is no free lunch. But can be important, serial ports can be slow enough to make your entire program unresponsive to user input. Not usually an issue in a console mode program or when you use a separate thread.

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

You can call ReadLine() in your DataReceived event handler as well, that's desert. That can technically cause deadlock, you should use the ReadTimeout property.

你也可以在你的 DataReceived 事件处理程序中调用 ReadLine() ,这是沙漠。这在技术上会导致死锁,您应该使用 ReadTimeout 属性。

But since you use the console, there's probably little reason to use DataReceived.

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

回答by Adam Zuckerman

When working with the .NET SerialPort implementation, you should NEVERtry to read from the serial port using the DataReceived event and any other method. ReadExistingand ReadLineboth use the same underlying MemoryStream. You will run into situations where you are pulling data off the MemoryStream from the ReadLine when the event interrupts causing you to attempt to read data that has already been removed from the stream.

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

Use one method or the other. Do no use both.

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

Hans Passant is correct about the ReadLineblocking your UI thread. You have two methods around that: use the DataReceivedevent; or place your code that handles the SerialPorton a separate thread.

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

Using the DataReceivedevent is usually preferable as .NET will run that on a worker thread automatically. You lose the freebie of the ReadLinethough. And you have to manually buffer the input if you need to perform read aheads (to give you something like the ReadLine functionality).

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