正确实现异步SerialPort读取

时间:2015-10-20 01:07:36

标签: c# serial-port async-await

我已经阅读了一些线程,建议使用port.BaseStream.ReadAsync()和waith async / await。我不清楚的是,实现这个目标的最佳方法是什么?

我仍然使用event_handler并让它异步/等待吗?

private async void myPort_DataReceived(object sender,      SerialDataReceivedEventArgs e)
        {
            byte[] buffer = new byte[myPort.BytesToRead];
            await (myPort.BaseStream.ReadAsync(buffer, 0, buffer.Length));
        }

或者是否完全忽略了事件处理程序,而是在循环中调用ReadAsync?

编辑:解析后,我将1)将数据发送到TCP服务器,2)将其写入sq3lite数据库。

1 个答案:

答案 0 :(得分:0)

Microsoft更新了API,该API可以实现相对简单的异步读写实现。请注意,您将不会实现看上去已完成的同步事件处理程序,而只要希望在COM端口上接收数据,就只需调用此函数即可:

public async Task<Stream> ReceiveData()
{
    var buffer = new byte[4096];
    int readBytes = 0;
    SerialPort port = new SerialPort(/* ... */);
    using (MemoryStream memoryStream = new MemoryStream())
    {
        while ((readBytes = await port.BaseStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
        {
            memoryStream.Write(buffer, 0, readBytes);
        }

        return memoryStream;
    }
}

这是另一种替代实现(请参见http://www.sparxeng.com/blog/software/must-use-net-system-io-ports-serialport),作者在其中解释了SerialPort DataReceived,BytesToRead和其他API成员的问题。他建议使用BaseStream来建议这种方法,而不是使用SerialPort API,因为他指出该API的设计,实施和测试不佳:

Action kickoffRead = null;
kickoffRead = delegate {
    port.BaseStream.BeginRead(buffer, 0, buffer.Length, delegate (IAsyncResult ar) {
        try {
            int actualLength = port.BaseStream.EndRead(ar);
            byte[] received = new byte[actualLength];
            Buffer.BlockCopy(buffer, 0, received, 0, actualLength);
            raiseAppSerialDataEvent(received);
        }
        catch (IOException exc) {
            handleAppSerialError(exc);
        }
        kickoffRead();
    }, null);
};
kickoffRead();

请注意,我发现将BCL与BaseStream一起使用时,性能改善比使用SerialPort API改善了多个数量级。