SerialPort.Read(byte [],int32,int32)没有阻塞但我想要它 - 我该如何实现?

时间:2013-05-08 11:49:13

标签: c# serial-port blocking

我正在编写一个与一台测试设备交谈的界面。设备通过串行端口进行通信,并对发送的每个命令以已知的字节数进行响应。

我目前的结构是:

  • 发送命令
  • 读回指定字节数
  • 继续申请

但是,当我使用SerialPort.Read(byte [],int32,int32)时,该函数没有阻塞。因此,例如,如果我调用MySerialPort.Read(byteBuffer, 0, bytesExpected);,则函数返回的值小于指定的bytesExpected。这是我的代码:

public bool ReadData(byte[] responseBytes, int bytesExpected, int timeOut)
{
    MySerialPort.ReadTimeout = timeOut;
    int bytesRead = MySerialPort.Read(responseBytes, 0, bytesExpected);
    return bytesRead == bytesExpected;
}

我称这种方法是这样的:

byte[] responseBytes = new byte[13];
if (Connection.ReadData(responseBytes, 13, 5000))
    ProduceError();

我的问题是,我似乎无法像我所说的那样读取完整的13个字节。如果我在Thread.Sleep(1000)之前放置SerialPort.Read(...),一切正常。

如何强制Read方法阻止,直到超出timeOut或读取指定的字节数?

3 个答案:

答案 0 :(得分:11)

这是预期的;大多数IO API允许您指定上部绑定 - 它们只需返回至少一个字节,除非它是EOF,在这种情况下它们可以返回非正值。为了补偿,你循环:

public bool ReadData(byte[] responseBytes, int bytesExpected, int timeOut)
{
    MySerialPort.ReadTimeout = timeOut;
    int offset = 0, bytesRead;
    while(bytesExpected > 0 &&
      (bytesRead = MySerialPort.Read(responseBytes, offset, bytesExpected)) > 0)
    {
        offset += bytesRead;
        bytesExpected -= bytesRead;
    }
    return bytesExpected == 0;
}

唯一的问题是,您可能需要通过使用Stopwatch或类似内容来减少每次迭代的超时,以查看已经过了多长时间。

请注意,我还删除了ref上的responseBytes - 您不需要它(您不会重新分配该值)。

答案 1 :(得分:1)

尝试将超时更改为InfiniteTimeout

答案 2 :(得分:0)

如果在SerialPort.ReadTimeout之前没有可用的字节,则预计SerialPort.Read会抛出TimeoutException。 因此,此方法准确读取所需的数字或字节,或引发异常:

    public byte[] ReadBytes(int byteCount) {
        try
        {
            int totBytesRead = 0;
            byte[] rxBytes = new byte[byteCount];
            while (totBytesRead < byteCount) {
                int bytesRead = comPort.Read(rxBytes, totBytesRead, byteCount - totBytesRead);
                totBytesRead += bytesRead;
            }



            return rxBytes;
        }
        catch (Exception ex){

            throw new MySerialComPortException("SerialComPort.ReadBytes error", ex);            
        }
    }