问题
I'm writing an interface for talking to a piece of test equipment. The equipment talks over a serial port and responds with a known number of bytes to each command I send it.
My current structure is:
- Send command
- Read number of specified bytes back
- Proceed with application
However, when I used SerialPort.Read(byte[], int32, int32), the function is not blocking. So, for example, if I call MySerialPort.Read(byteBuffer, 0, bytesExpected);, the function returns with less than the specified number of bytesExpected. Here is my code:
public bool ReadData(byte[] responseBytes, int bytesExpected, int timeOut)
{
MySerialPort.ReadTimeout = timeOut;
int bytesRead = MySerialPort.Read(responseBytes, 0, bytesExpected);
return bytesRead == bytesExpected;
}
And I call this method like this:
byte[] responseBytes = new byte[13];
if (Connection.ReadData(responseBytes, 13, 5000))
ProduceError();
My problem is that I can't ever seem to get it to read the full 13 bytes like I am telling it. If I put a Thread.Sleep(1000) right before my SerialPort.Read(...) everything works fine.
How can I force the Read method to block until either the timeOut is exceeded or the specified number of bytes are read?
回答1:
That is expected; most IO APIs allow you to specify the upper bound only - they are simply required to return at-least-one byte, unless it is an EOF in which case they can return a non-positive value. To compensate, you loop:
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;
}
The only problem is you might need to reduce the timeout per iteration, by using a Stopwatch or similar to see how much time has passed.
Note that I also removed the ref on responseBytes - you don't need that (you don't re-assign that value).
回答2:
Try changing the timeout to InfiniteTimeout.
回答3:
SerialPort.Read is expected to throw a TimeoutException in case no bytes are available before SerialPort.ReadTimeout. So this method reads exactly the desired number or bytes, or throws an exception:
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);
}
}
来源:https://stackoverflow.com/questions/16439897/serialport-readbyte-int32-int32-is-not-blocking-but-i-want-it-to-how-do