SerialPort.BaseStream.ReadAsync缺少第一个字节 [英] SerialPort.BaseStream.ReadAsync missing the first byte
问题描述
我正在尝试在.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屋!