刚刚读取刚打开的SerialPort时,只读取一个字节

奇怪的问题。

当我使用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()中,没有所有数据可用但只有一次

因为在读取时,其他字节没有到达,它将只读取一个字节,因为队列中只有一个字节。 因此,如果存在至少一个字节,它将不会等待所需的字节数,因为超时已发生,但它不会抛出exception。 如果没有,它将抛出超时exception。 因此,您应该尝试阅读,直到您根据需要读取多个字节(在您的情况下为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 } } 

有几种方法可以解决这个问题。 如果您希望从发送的命令回复,则在调用serialPort.Write()之前应该至少hibernate250毫秒。在调用serilPort.Read()之前。 或者,如果您知道设备发送回的字节数,可以使用serialPort.BytesToRead属性来延迟读取,直到您期望的字节数可用。 如果您正在使用DataReceived事件,则可以设置serialPort.ReceivedBytesThreshold(默认值为1)以防止在预期的字节数可用之前引发事件。 请记住,不保证serialPort.Read方法返回请求的字节数。 这就是serialPort.Read方法返回一个整数的原因,该整数是读取的实际字节数。

我发现我的解决方案,这有助于:

 ireadCount = serialPort.Read(readBuffer, 0, serialPort.ReadBufferSize); Thread.Sleep(1);//This can be removed, just use it in case need time to complete the reception. ireadCount = serialPort.Read(readBuffer, 1, serialPort.ReadBufferSize-1); ireadCount +=1; 

这样我可以从外部设备获得整个响应,而不会丢失第一个字节。

问候。-