奇怪的问题。

当我使用SerialPort.Read()从com-port读取数据时,如果数据到达,则在第一次调用时仅读取一个字节,而忽略了count参数和超时内可用的字节数。所有进一步的阅读都可以,只有第一个有问题

使用SerialPort.DiscardInBuffer()或关闭/打开(重新打开)com-port将再次引起第一次读取的问题。

这是一些代码:

var port = new SerialPort();
port.PortName = "com2";
port.BaudRate = 9600;
port.WriteTimeout = 1000;
port.ReadTimeout = 1000;
port.Open();

// ... send some data first

var read = new byte[10];
if (port.Read(read, 0, read.Length) != read.Length)
{
    // always here at first reading no matter what
}

// ... send some data again

if (port.Read(read, 0, read.Length) != read.Length)
{
    // not here anymore (unless error)
}


如果在调用Read()时已经可以读取指定数量的数据,则不会出现问题。



一些解释。

Read()是同步读取。当接收到指定数量的数据或超时到期时,它将返回。看来,只有在收到零字节的情况下才会抛出TimeoutException。如果在读取请求的数据量之前超时已过期,则函数将返回读取的字节数。因此,必须将返回值与请求的值进行比较,以查看读取是否正常。

但是第一个电话有一个问题:


  如果在超时期间到达0个字节,则第一个调用正确等待超时并触发TimeoutException。如果至少有1个字节到达,则函数将立即结束,而忽略超时和请求读取的字节总数。


这就是我的看法。我错了吗?我该怎么办?



一些更多的测试。插入Thread.Sleep()以确保在调用Read()时将有所有可用数据,从而使问题消失。

从逻辑上讲,让我们只为第一次通话添加睡眠。好极了。什么????现在,第二个电话和仅第二个电话出现问题。换句话说,第一个Read()会出现问题,它将无法获得所有可用数据,而只有一次。

最佳答案

因为在读取时,其他字节没有到达,所以它将仅读取一个字节,因为队列中只有一个字节。因此,如果存在至少一个字节,它将不会等待所需的字节数,因为发生了超时,但不会引发异常。如果不存在,它将抛出超时异常。因此,您应该尝试读取,直到读取所需的字节数为止(本例中为10)。您可以尝试使用以下方法:

int count = 0;
var read = new byte[10];
while ((count += port.Read(read, count, read.Length - count)) != read.Length) ;


但是如果发生超时怎么办,也许可以增强代码:

int count = 0;
var read = new byte[10];
while (count < read.Length)
{
    try
    {
        count += port.Read(read, count, read.Length - count);
    }
    catch (TimeoutException te)
    {
        //maybe increase ReadTimeout or something, use exponential backoff, your call
    }
}

关于c# - 读取刚刚打开的SerialPort时仅读取一个字节,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24676317/

10-12 00:17
查看更多