简体   繁体   English

SerialPort.BaseStream.ReadAsync缺少第一个字节

[英]SerialPort.BaseStream.ReadAsync missing the first byte

I am trying to use the SerialPort class in .net. 我试图在.net中使用SerialPort类。

I've opted to keep my service async, so I am using the async-methods on SerialPort.BaseStream . 我选择保持我的服务异步,所以我在SerialPort.BaseStream上使用async-methods。

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. 在我的异步方法中,我将一个byte []写入串口,然后开始读取,直到我在n毫秒内没有收到任何数据,并返回该结果。

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. 但问题是,除了打开串口后的第一个回复之外,我似乎错过了所有回复中的第一个字节。

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." 然而,这经常导致"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? 是否有一种更智能的方法来异步实现相同的目标?

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. 仅仅因为你没有观察到最后一个ReadAsync()并不意味着它被取消,它仍然在运行,这显然表现在它读取下面消息的第一个字节。

What you should do is to cancel the last ReadAsync() by using a CancellationToken . 你应该做的是使用CancellationToken取消最后一次ReadAsync() 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. 请注意,超时和读取之间可能存在竞争,但我假设如果超时已过,则无法在没有其他写入的情况下完成读取。

The code would look like this: 代码如下所示:

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. 请注意,原因和解决方案都是我的猜测,我当然可能错误地认为其中一个或两个都是错误的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM