mik*_*ner 7 asynchronous serial-port blocking
我有一个类,它使用C#中的DataReceived事件处理程序从串口读取.当我收到数据时,我知道标题将有5个字节,所以我不想对数据做任何事情,直到我至少有.我目前的代码如下:
while (serialPort.BytesToRead<5)
{
//Do nothing while we have less bytes than the header size
}
//Once at least 5 bytes are received, process header
Run Code Online (Sandbox Code Playgroud)
据我了解,这段代码是阻塞的,需要改进.我正在寻找有关如何做到这一点的建议.DataReceived事件处理程序中的另一个事件处理程序是否合适?
jos*_*lmt 13
使用异步编程(不要忘记首先将应用程序定位到.NET Framework 4.5).
在这里,您将我的实现作为扩展方法SerialPort.
using System;
using System.IO.Ports;
using System.Threading.Tasks;
namespace ExtensionMethods.SerialPort
{
public static class SerialPortExtensions
{
public async static Task ReadAsync(this SerialPort serialPort, byte[] buffer, int offset, int count)
{
var bytesToRead = count;
var temp = new byte[count];
while (bytesToRead > 0)
{
var readBytes = await serialPort.BaseStream.ReadAsync(temp, 0, bytesToRead);
Array.Copy(temp, 0, buffer, offset + count - bytesToRead, readBytes);
bytesToRead -= readBytes;
}
}
public async static Task<byte[]> ReadAsync(this SerialPort serialPort, int count)
{
var buffer = new byte[count];
await serialPort.ReadAsync(buffer, 0, count);
return buffer;
}
}
}
Run Code Online (Sandbox Code Playgroud)
在这里如何阅读:
public async void Work()
{
try
{
var data = await serialPort.ReadAsync(5);
DoStuff(data);
}
catch(Exception excepcion)
{
Trace.WriteLine(exception.Message);
}
}
Run Code Online (Sandbox Code Playgroud)
这会烧掉100%核心,你不想这样做.正确的方法是让程序阻塞Read()调用.你写的类似于:
private byte[] rcveBuffer = new byte[MaximumMessageSize];
private int rcveLength;
void ReceiveHeader() {
while (rcveLength < 5) {
rcveLength += serialPort.Read(rcveBuffer, rcveLength, 5 - rcveLength);
}
}
Run Code Online (Sandbox Code Playgroud)
或者,如果您使用DataReceived事件,则它可能如下所示:
private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) {
if (e.EventType != System.IO.Ports.SerialData.Chars) return;
if (rcveLength < 5) {
rcveLength += serialPort.Read(rcveBuffer, rcveLength, 5 - rcveLength);
}
if (rcveLength >= 5) {
// Got the header, read the rest...
}
}
Run Code Online (Sandbox Code Playgroud)
在收到整个消息并进行处理后,不要忘记将rcveLength设置回0.