C# 异步串行端口读取
我有一个类,它使用C#中的DataReceived事件处理程序从串行端口读取数据。当我收到数据时,我知道报头将有5个字节,所以在至少有5个字节之前,我不想对数据做任何事情。我目前的代码如下:C# 异步串行端口读取,c#,asynchronous,serial-port,blocking,C#,Asynchronous,Serial Port,Blocking,我有一个类,它使用C#中的DataReceived事件处理程序从串行端口读取数据。当我收到数据时,我知道报头将有5个字节,所以在至少有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
while (serialPort.BytesToRead<5)
{
//Do nothing while we have less bytes than the header size
}
//Once at least 5 bytes are received, process header
while(serialPort.BytesToRead会燃烧100%的内核,您不想这样做。正确的方法是将程序块放在Read()调用上。您可以这样编写:
private byte[] rcveBuffer = new byte[MaximumMessageSize];
private int rcveLength;
void ReceiveHeader() {
while (rcveLength < 5) {
rcveLength += serialPort.Read(rcveBuffer, rcveLength, 5 - rcveLength);
}
}
private byte[]rcveBuffer=新字节[MaximumMessageSize];
私人住宅;
void ReceiveHeader(){
而(rcveLength<5){
rcveLength+=serialPort.Read(rcveBuffer,rcveLength,5-rcveLength);
}
}
或者,如果使用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...
}
}
private void serialPort\u DataReceived(对象发送方,System.IO.Ports.SerialDataReceivedEventArgs e){
if(e.EventType!=System.IO.Ports.SerialData.Chars)返回;
如果(rcveLength<5){
rcveLength+=serialPort.Read(rcveBuffer,rcveLength,5-rcveLength);
}
如果(rcveLength>=5){
//得到标题,读剩下的。。。
}
}
在获得整个消息并对其进行处理后,不要忘记将rcveLength设置回0。使用异步编程(不要忘记首先将应用程序定向到.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;
}
}
}
Hans,非常感谢您的回复。如果最初收到的字节少于5个,它似乎会停止,我需要弄清楚如何“循环”再次返回。例如,我总是读取一个20字节的数组。串行端口通常一次提取所有20个字节,但有时它会提取,比如1个字节,然后是19个字节。在这种情况下,上面的代码读取1个字节,然后停止。我是否需要在某个地方睡眠,以便为剩余的数据输入时间?当剩下的字节到达了。你们不应该再做类似“循环返回”这样的事情当然,我不知道为什么不会发生这种情况。一些你实际读取字节但没有实际使用它们的错误是常见的。FWI:我不得不使用System.IO.Ports.SerialPort SerialPort
而不是SerialPort SerialPort
。我不知道我是否搞错了什么,但它只想这样工作。是的,我正在使用系统.IO.port
——但是,我仍然无法让它读取任何内容:(但是我发现ReadTimeout
在BaseStream
上不起作用,下面是如何添加ad超时:
public async void Work()
{
try
{
var data = await serialPort.ReadAsync(5);
DoStuff(data);
}
catch(Exception excepcion)
{
Trace.WriteLine(exception.Message);
}
}