Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/288.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# SerialPort.BaseStream.ReadAsync缺少第一个字节_C#_Asynchronous_Stream_Serial Port_Async Await - Fatal编程技术网

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

C# SerialPort.BaseStream.ReadAsync缺少第一个字节,c#,asynchronous,stream,serial-port,async-await,C#,Asynchronous,Stream,Serial Port,Async Await,我正在尝试使用.net中的SerialPort类 我选择保持我的服务异步,所以我在SerialPort.BaseStream上使用异步方法 在我的异步方法中,我将一个字节[]写入串行端口,然后开始读取,直到在n毫秒内没有收到任何数据,然后返回结果 然而,问题是,除了打开串行端口后的第一个回复之外,我似乎错过了所有回复中的第一个字节 如果在每次响应(读取)后关闭端口,并在执行新请求(写入)前再次打开端口,则第一个字节不会丢失。但是,这通常会导致“端口'COM4'的访问被拒绝。”异常,如果我试图在关

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

我选择保持我的服务异步,所以我在
SerialPort.BaseStream
上使用异步方法

在我的异步方法中,我将一个字节[]写入串行端口,然后开始读取,直到在n毫秒内没有收到任何数据,然后返回结果

然而,问题是,除了打开串行端口后的第一个回复之外,我似乎错过了所有回复中的第一个字节

如果在每次响应(读取)后关闭端口,并在执行新请求(写入)前再次打开端口,则第一个字节不会丢失。但是,这通常会导致
“端口'COM4'的访问被拒绝。”
异常,如果我试图在关闭后过早打开端口。对于每次写入/读取,似乎也没有必要打开/关闭

我的方法基本上是这样的:

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;
}
专用异步任务SendRequestAsync(字节[]请求)
{    
//写下请求
wait_serialPort.BaseStream.WriteAsync(请求,0,请求.长度);
var buffer=新字节[buffer_SIZE];
bool receiveComplete=false;
var bytesRead=0;
//从串行端口读取数据
做
{
var responseTask=_serialPort.BaseStream.ReadAsync(缓冲区、字节读、缓冲区大小-字节读);
if(wait Task.wheny(responseTask,Task.Delay(300))==responseTask)
{
字节读取+=响应任务结果;
}
其他的
receiveComplete=true;
}而(!receiveComplete);
var响应=新字节[字节读取];
复制(缓冲区,0,响应,0,字节读取);
返回响应;
}

我这样做有什么明显的错误吗?有没有更聪明的方法来异步实现相同的功能?

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

您应该做的是使用
CancellationToken
取消最后一个
ReadAsync()
。请注意,超时和读取之间可能存在竞争,但我假设如果超时已过,则在不进行另一次写入的情况下,读取不可能完成

代码如下所示:

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);

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

做一个
。结果
之后,当任何
时,所有的
总是让我畏缩,我知道这应该不会有问题,但我仍然不喜欢它。我总是喜欢做
bytesRead+=wait responseTask
,由于任务已完成,
wait
没有开销,但是您可以利用抛出的未包装异常,而不是从
获取
aggregateeexception
。如果您确实收到错误,则结果
。您确定在300毫秒超时后流中没有字节吗?你怎么知道你漏掉了第一个字节?第一个字节在某种程度上是特殊的吗?我问这个问题的原因是,可能前一个响应还剩下字节,所以在第一次读取之后的每次读取实际上都包含第一个字节,但是在前一个请求的剩余字节之后。您可能需要在每个请求之前刷新流。我知道缺少第一个字节,因为每个响应都应该以ASCII字符“$”(NMEA消息)开头。我现在已经切换到使用同步API,但是在后台任务中运行它,并且它正在工作。虽然我不喜欢这个解决方案。。