.net - VB.Net SerialPort 读取返回碎片数据集

标签 .net vb.net serial-port system.net virtual-serial-port

问题

我有一个 USB 设备,可以在 Windows 上创建虚拟串行端口。我正在使用 VB.Net 从端口写入和读取。我的设备以特定大小的字节集进行响应,但我发现 SerialPort.Read(byte-array,offset,number-bytes) 不会返回完整的字节数,但它也不会超时或生成异常。重复调用会返回额外的片段(最多需要 3 次调用)。我不明白为什么这个读取方法的行为如此?它是否认为请求的字节数只是一个建议? :-)。我希望它会等待完成整个请求,除非它首先超时。

使用 pySerial 的 Python 代码没有有同样的问题。

那么,我在这里做错了什么?是我期待太高了吗?

一些场景是:

  1. 我向端口写入命令并期望得到 4 个字节的响应。我首先获得 1 个字节,然后在后续调用中获得 3 个字节。
  2. 我编写了一条命令,期望得到 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/

相关文章:

c# - 替换第一个数字 block 后的所有字符

c# - 检测 JSON 中 null 属性和省略属性之间的差异

c# - 使用visual studio进行动态调试

asp.net - 如何获取更改后的文本的值

.net - 在 vb.net 中最佳使用 MID 和 INSTR

python - 通过蓝牙将 Arduino 连接到 Python

c# - 在 xml 文档中,我可以插入对方法组的引用吗?如何?

c# - 如何显式运行未知类型的静态构造函数?

Mysql查询不插入值

bash - 如何通过脚本退出 minicom