问题
我有一个 USB 设备,可以在 Windows 上创建虚拟串行端口。我正在使用 VB.Net 从端口写入和读取。我的设备以特定大小的字节集进行响应,但我发现 SerialPort.Read(byte-array,offset,number-bytes) 不会返回完整的字节数,但它也不会超时或生成异常。重复调用会返回额外的片段(最多需要 3 次调用)。我不明白为什么这个读取方法的行为如此?它是否认为请求的字节数只是一个建议? :-)。我希望它会等待完成整个请求,除非它首先超时。
使用 pySerial 的 Python 代码没有有同样的问题。
那么,我在这里做错了什么?是我期待太高了吗?
一些场景是:
- 我向端口写入命令并期望得到 4 个字节的响应。我首先获得 1 个字节,然后在后续调用中获得 3 个字节。
- 我编写了一条命令,期望得到 21120 字节的响应。我通过 3 次调用从端口读取数据,分别得到 1、12671 和 8448 字节。
以下是我的代码的一些摘录:
Private Sub SetupVirtualSerialPort()
Dim portName As String = "COM" + (m_DeviceContext * -1).ToString
Const baud As Int32 = 9600 '7680000
Const parity As Parity = parity.None
Const databits As Int32 = 8
Const stopbits As StopBits = stopbits.One
m_SerialPort = New SerialPort(portName, baud, parity, databits, stopbits)
m_SerialPort.WriteTimeout = VSPtimeout
m_SerialPort.ReadTimeout = VSPtimeout
m_SerialPort.ReadBufferSize = 2 * RETURN_BUFFER_SIZE
m_SerialPort.WriteBufferSize = 2 * COMMAND_BUFFER_SIZE
m_SerialPort.Open()
' Register event handlers
AddHandler m_SerialPort.ErrorReceived, AddressOf m_DriverInterface.Handle_VSP_Error
End Sub
Public Function WriteReadVSPort(ByVal commandLength As Int32, ByVal returnLength As Int32) As Int32
Const RetryLimit As Int32 = 5
Dim NumberRetries As Int32 = 0
Dim Offset As Int32 = 0
Dim ExceptionOccurred As Boolean = False
Dim NumberBytes As Int32 = 0
Try ' Writing
m_SerialPort.Write(m_CommandBuffer, 0, commandLength)
Catch exc As InvalidOperationException
MessageBox.Show("InvalidOperationException", Application.ProductName)
ExceptionOccurred = True
Catch exc As TimeoutException
MessageBox.Show("TimeoutException", Application.ProductName)
ExceptionOccurred = True
End Try
If Not ExceptionOccurred Then
Try ' Reading
' Working around a problem here: reads are returning fewer
' bytes than requested, though not signalling a timeout exception.
' Therefore, we retry if we got fewer bytes than expected, up to five times.
While NumberRetries < RetryLimit And returnLength > Offset
NumberBytes = m_SerialPort.Read(m_ReturnBytes, Offset, returnLength - Offset)
Offset += NumberBytes
NumberRetries += 1
If returnLength <> NumberBytes Then
System.Diagnostics.Debug.Print("Number of bytes read (" & NumberBytes &
") not what was requested (" & returnLength & "). Accumulated " & Offset)
End If
End While
Catch exc As InvalidOperationException
MessageBox.Show("InvalidOperationException", Application.ProductName)
ExceptionOccurred = True
Catch exc As TimeoutException
MessageBox.Show("TimeoutException", Application.ProductName)
ExceptionOccurred = True
End Try
If ExceptionOccurred Then
Return 1
Else
Return 0
End If
End Function
谢谢。
最佳答案
这对于处理 IO(包括流和端口)来说是完全正常的。基本上,您需要检查返回值和循环。例如:
int offset = 0, read, remaining = ...;
while(remaining > 0 &&
(read = source.Read(buffer, offset, remaining) > 0)
{
offset += read;
remaining -= read;
}
if(remaining > 0) throw new EndOfStreamException();
如果您的消息不是固定长度,您可能需要添加长度前缀(在每条消息之前)或消息分隔符(在每条消息之后)。
关于.net - VB.Net SerialPort 读取返回碎片数据集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7797251/