SerialPort.BaseStream.ReadAsync缺少第一个字节 [英] SerialPort.BaseStream.ReadAsync missing the first byte

查看:82
本文介绍了SerialPort.BaseStream.ReadAsync缺少第一个字节的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在.net中使用SerialPort类.

I am trying to use the SerialPort class in .net.

我选择使服务保持异步,因此我在SerialPort.BaseStream上使用了异步方法.

I've opted to keep my service async, so I am using the async-methods on SerialPort.BaseStream.

在我的异步方法中,我向串行端口写入一个byte [],然后开始读取,直到在n毫秒内没有收到任何其他数据为止,然后返回该结果.

In my async method, I write a byte[] to the serial port, then start reading until I haven't received any more data in n milliseconds, and return that result.

但是,问题是,除了打开串行端口后的第一个答复,我似乎错过了所有答复中的第一个字节.

The problem is, however, that I seem to miss the first byte in all replies other than the very first reply after opening the serial port.

如果在每次响应(读取)之后关闭端口,然后在执行新请求(写入)之前再次打开端口,则第一个字节不会丢失.但是,如果我尝试在关闭后过早打开端口,通常会导致"Access to the port 'COM4' is denied."异常.似乎也没有必要为每次写/读都打开/关闭.

If I close the port after every response (Read), and open it again before doing a new request (Write), the first byte is not missing. This, however, often results in a "Access to the port 'COM4' is denied." exception, if I try to open the port too soon after closing. It also seems very unnecessary to open/close for every write/read.

这基本上就是我的方法:

This is basically what my method looks like:

private async Task<byte[]> SendRequestAsync(byte[] request)
{    
    // Write the request
    await _serialPort.BaseStream.WriteAsync(request, 0, request.Length);

    var buffer = new byte[BUFFER_SIZE];
    bool receiveComplete = false;
    var bytesRead = 0;

    // Read from the serial port
    do
    {
        var responseTask = _serialPort.BaseStream.ReadAsync(buffer, bytesRead, BUFFER_SIZE - bytesRead);
        if (await Task.WhenAny(responseTask, Task.Delay(300)) == responseTask)
        {
            bytesRead += responseTask.Result;
        }
        else
            receiveComplete = true;


    } while (!receiveComplete);

    var response = new byte[bytesRead];
    Array.Copy(buffer, 0, response, 0, bytesRead);

    return response;
}

我做这件事的方式上有明显的错误吗?有没有更聪明的异步方式来实现相同目标?

Is there anything obviously wrong in the way I am doing this? Is there a smarter way to achieve the same asynchronously?

推荐答案

仅仅因为您没有观察到最后一个ReadAsync()并不意味着它被取消,它仍在运行,显然是通过读取第一个字节来体现的以下消息.

Just because you're not observing the last ReadAsync() doesn't mean it gets canceled, it's still running, which apparently manifests by it reading the first byte of the following message.

您应该做的是使用CancellationToken取消最后一个ReadAsync().请注意,在超时和读取之间可能存在竞争,但是我假设如果超时已过去,那么在没有其他写入的情况下不可能完成读取.

What you should do is to cancel the last ReadAsync() by using a CancellationToken. Note that there is a possible race between the timeout and the read, but I'm assuming that if the timeout elapsed, it's not possible for the read to complete without another write.

代码如下:

var cts = new CancellationTokenSource();

do
{
    var responseTask = _serialPort.BaseStream.ReadAsync(
        buffer, bytesRead, BUFFER_SIZE - bytesRead, cts.Token);

    if (await Task.WhenAny(responseTask, Task.Delay(300)) == responseTask)
    {
        bytesRead += responseTask.Result;
    }
    else
    {
        cts.Cancel();
        receiveComplete = true;
    }
} while (!receiveComplete);

请注意,原因和解决方案都是我的猜测,当然我可能对其中一个或两个都错了.

Note that both the cause and the solution are my guesses, it's certainly possible that I'm wrong about one or both of them.

这篇关于SerialPort.BaseStream.ReadAsync缺少第一个字节的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆