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