Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vb.net/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
VB.Net SerialPort读取正在返回碎片数据集 问题_.net_Vb.net_Serial Port_System.net_Virtual Serial Port - Fatal编程技术网

VB.Net SerialPort读取正在返回碎片数据集 问题

VB.Net SerialPort读取正在返回碎片数据集 问题,.net,vb.net,serial-port,system.net,virtual-serial-port,.net,Vb.net,Serial Port,System.net,Virtual Serial Port,我有一个USB设备,可以在Windows上创建一个虚拟串行端口。我正在使用VB.Net从端口读写。我的设备以特定大小的字节集响应,但我发现SerialPort.Read(字节数组、偏移量、字节数)不会返回完整的字节数,但也不会超时或生成异常。重复调用会返回额外的片段(最多需要3个调用)。我不明白为什么这个read方法的行为如此?它是否认为请求的字节数只是一个建议?:-)。我希望它会等待完成整个请求,除非它先超时 使用pySerial的Python代码没有相同的问题 那么,我做错了什么?我是不是期

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

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

那么,我做错了什么?我是不是期望太高了?

有些情况是:
  • 我向端口写入一个命令,希望得到4个字节的响应。我先得到1个字节,然后在后续调用中得到3个字节
  • 我写了一个命令,期望得到21120字节的响应。我在3次调用中从端口读取112671和8448字节
  • 以下是我的代码的一些摘录:
    专用子设置VirtualSerialPort()
    Dim端口名为String=“COM”+(m_DeviceContext*-1)。ToString
    常量波特率为Int32=9600'7680000
    常量奇偶校验为奇偶校验=奇偶校验。无
    常量数据位为Int32=8
    常量停止位为停止位=停止位。1
    m_SerialPort=新的串行端口(端口名、波特率、奇偶校验、数据位、停止位)
    m_SerialPort.WriteTimeout=VSPtimeout
    m_SerialPort.ReadTimeout=VSPtimeout
    m_SerialPort.ReadBufferSize=2*返回缓冲区大小
    m_SerialPort.WriteBufferSize=2*命令缓冲区大小
    m_SerialPort.Open()
    '注册事件处理程序
    AddHandler m_SerialPort.ErrorReceived,m_DriverInterface.Handle_VSP_错误的地址
    端接头
    公共函数WriteReadVSPort(ByVal命令长度为Int32,ByVal返回长度为Int32)为Int32
    常数RetryLimit为Int32=5
    尺寸编号尝试为Int32=0
    尺寸偏移为Int32=0
    Dim异常发生为布尔值=False
    将数字字节设置为Int32=0
    试着写
    m_SerialPort.Write(m_CommandBuffer,0,commandLength)
    捕获exc作为InvalidOperationException
    MessageBox.Show(“InvalidOperationException”,Application.ProductName)
    ExceptionOccurred=真
    捕获exc作为TimeoutException
    MessageBox.Show(“TimeoutException”,Application.ProductName)
    ExceptionOccurred=真
    结束尝试
    如果没有例外,那么
    试着阅读
    “解决了一个问题:读取返回的数据越来越少
    '字节,但不表示超时异常。
    '因此,如果得到的字节比预期的少,我们将重试,最多重试五次。
    而NumberRetriesOffset
    NumberBytes=m_SerialPort.Read(m_ReturnBytes,Offset,returnLength-Offset)
    偏移量+=数字节
    NumberRetries+=1
    如果返回长度NumberBytes,则
    System.Diagnostics.Debug.Print(“读取的字节数”(&NumberBytes&
    “”不是请求的(“&returnLength&”)。累计“&Offset)
    如果结束
    结束时
    捕获exc作为InvalidOperationException
    MessageBox.Show(“InvalidOperationException”,Application.ProductName)
    ExceptionOccurred=真
    捕获exc作为TimeoutException
    MessageBox.Show(“TimeoutException”,Application.ProductName)
    ExceptionOccurred=真
    结束尝试
    如果发生例外情况,则
    返回1
    其他的
    返回0
    如果结束
    端函数
    

    谢谢。

    这对于处理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();
    

    如果您的消息不是固定长度的,则可能需要添加长度前缀(在每个前缀之前)或消息分隔符(在每个前缀之后)。

    我建议使用DataReceived事件,并使代码事件受驱动,而不是循环。在一次读取操作中,我发现我的21120字节消息的虚拟串行端口仍然无法工作。适当缩短消息长度。然而,当我将串行端口数据接收阈值设置为21119字节,并将串行端口读取缓冲区设置为消息大小的10倍时,我发现 1.DataReceived事件将被触发,只有12672字节可用(不是21119字节),并且在对完整大小执行Read()时返回相同的数字。 2.在字节数不等于阈值的情况下,如果我当时不进行读取,则不会触发进一步的DataReceived事件 3.但是,如果(且仅当)我读取了12672字节,则另一个DataReceived事件将与剩余的8448字节一起出现

    我不明白为什么会这样。欢迎进一步评论

    然而,我想我会为了他人的利益而分享我当前的代码

    一些类变量是:

    Private m_SerialPort As SerialPort = Nothing
    Private Debug As Int16
    Private m_CommandBuffer(COMMAND_BUFFER_SIZE) As Byte
    Private m_ReturnBytes(RETURN_BUFFER_SIZE) As Byte
    Private m_WaitingOnBytes As Int32
    Private m_VSP_Offset As Int32 = 0
    Private m_waitHandle As New System.Threading.ManualResetEvent(True) ' Initialize to signaled
    Private m_waitHandle2 As New System.Threading.ManualResetEvent(False) ' Initialize to UN-signaled
    
    事件处理程序子例程

    Public Sub Handle_VSP_DataReceived_Dev(ByVal sender As System.Object, ByVal e As System.EventArgs)
      Dim NumberBytes As Int32
    
      If m_SerialPort.BytesToRead > 0 And m_SerialPort.BytesToRead >= m_WaitingOnBytes Then
        ' This handles the case where the event was triggered, there was data and its length matched
        ' or exceeded the requested amount.
        System.Diagnostics.Debug.Print("DR-Dev: Bytes to read: " & m_SerialPort.BytesToRead & ", waiting for: " & m_WaitingOnBytes)
        NumberBytes = m_SerialPort.Read(m_ReturnBytes, m_VSP_Offset, m_WaitingOnBytes)
        System.Diagnostics.Debug.Print("DR-Dev: got " & NumberBytes & " bytes, released wait handle")
        m_WaitingOnBytes = 0
        m_waitHandle.Set() ' Release the wait handle so the thread running WriteReadVSPort can proceed
      ElseIf m_SerialPort.BytesToRead > 0 And m_WaitingOnBytes > 0 Then
        ' Handle the case where the full request is not delivered. Note: 
        ' This should not need to be done, but it seems that the 
        ' Serial Port is sending the event before all the data is 
        ' received and the threshold is crossed and then not 
        ' sending another event until the buffer is read.
        ' So, here we do a partial read, if we are waiting on a
        ' read operation and adjust the offset and remaining bytes
        ' we are waiting for.
        System.Diagnostics.Debug.Print("DR-Dev: Bytes to read: " & m_SerialPort.BytesToRead & ", waiting for: " & m_WaitingOnBytes)
        NumberBytes = m_SerialPort.Read(m_ReturnBytes, m_VSP_Offset, m_WaitingOnBytes)
        If NumberBytes = m_WaitingOnBytes Then
          ' We actually got all the data, though the serial port did not report it had it ready. Fine, 
          ' proceed as above
          System.Diagnostics.Debug.Print("DR-Dev: got " & m_WaitingOnBytes & " bytes, released wait handle")
          m_WaitingOnBytes = 0
          m_waitHandle.Set() ' Release the wait handle so the thread running WriteReadVSPort can proceed
        Else ' Mark this as a partial read
          System.Diagnostics.Debug.Print("DR-Dev: got partial " & NumberBytes & " while waiting for: " &
            m_WaitingOnBytes & " bytes, continue to hold WriteReadVSPort")
          m_WaitingOnBytes -= NumberBytes
          m_VSP_Offset += NumberBytes
        End If
      End If
    
    End Sub
    
    执行写入命令/读取响应活动的函数

    Public Function WriteReadVSPort(ByVal commandLength As Int32, ByVal returnLength As Int32) As Int32
    
      Dim ExceptionOccurred As Boolean = False
      Dim NumberBytes As Int32 = 0
      Dim RetriesRemaining As Int32 = 4
      Dim Finished As Boolean = False
    
      ' Important to set up for reading response before the command is written
      ' because another thread will handle the DataReceived event and process
      ' the received data without intervention from the thread executing
      ' this(subroutine.
      m_VSP_Offset = 0
      m_WaitingOnBytes = returnLength
      ' Set the DataReceived event threshold
      m_SerialPort.ReceivedBytesThreshold = m_WaitingOnBytes - 1
      ' Set waitHandle so it will block the thread executing this routine until the data is received
      m_waitHandle.Reset()
    
      Try '  Writing
        m_SerialPort.Write(m_CommandBuffer, 0, commandLength)
      Catch exc As InvalidOperationException
        MessageBox.Show("InvalidOperationException when writing to Serial Port COM" & -1 * DeviceContext, Application.ProductName)
        ExceptionOccurred = True
      Catch exc As TimeoutException
        MessageBox.Show("TimeoutException when writing to Serial Port COM" & -1 * DeviceContext, Application.ProductName)
        ExceptionOccurred = True
      End Try
    
      If Not ExceptionOccurred Then
    
        Try ' Reading all done by Event Handler
    
          ' wait for event handler to complete its job, running in another thread
          System.Diagnostics.Debug.Print("WR_VSP: waiting on waitHandle, bytes avail: " &
                  m_SerialPort.BytesToRead & ", want bytes: " & m_WaitingOnBytes)
    
          If m_waitHandle.WaitOne(VSPtimeout) Then
            ' The WaitOne call returned True, meaning that Handle_VSP_DataReceived_Dev was able to receive all the requested data
            System.Diagnostics.Debug.Print("WR_VSP: proceeding")
          Else
            ' The WaitOne call timed out. Give it some retries before throwing an exception
            While Not Finished And RetriesRemaining > 0
              System.Threading.Thread.Sleep(VSPtimeout)
              If m_SerialPort.BytesToRead > 0 And m_SerialPort.BytesToRead >= m_WaitingOnBytes Then
                NumberBytes = m_SerialPort.Read(m_ReturnBytes, m_VSP_Offset, m_WaitingOnBytes)
                System.Diagnostics.Debug.Print("WR_VSP: timeout mode, got " & m_WaitingOnBytes & " bytes")
                Finished = True
              Else
                RetriesRemaining -= 1
              End If
            End While
            If Not Finished Then
              Throw New TimeoutException("Device failed to send the requested number of bytes.")
            End If
          End If
    
        Catch exc As InvalidOperationException
          MessageBox.Show("InvalidOperationException when reading from Serial Port COM" & -1 * DeviceContext, Application.ProductName)
          ExceptionOccurred = True
        Catch exc As TimeoutException
          MessageBox.Show("TimeoutException when reading from Serial Port COM" & -1 * DeviceContext, Application.ProductName)
          ExceptionOccurred = True
        End Try
    
      End If
    
      If ExceptionOccurred Then
        Return 1
      Else
        Return 0
      End If
    
    End Function
    

    根据设计,SerialPort.Read()返回接收缓冲区中的任何内容。这通常很小,串行端口不是很快。继续调用Read(),直到得到足够的值为止。要将.Read()与.ReadExisting()进行什么对比?Read()返回字节,ReadExisting()返回字符串。非常不同的一壶鱼。如果这是“正常”,为什么要使用超时参数?这是在没有返回任何字节的情况下吗?在另一个论坛上,有人建议通过设置DataReceived事件的阈值、检查BytesToRead并使用DataReceived事件来提高我代码的效率。请注意,最近的代码运行速度比原始代码慢8倍左右。我发现平均每过10个街区,waitHandle就会超时。通过无情地调整不同的超时时间,我能够将性能恢复到我最初的水平
    Public Function WriteReadVSPort(ByVal commandLength As Int32, ByVal returnLength As Int32) As Int32
    
      Dim ExceptionOccurred As Boolean = False
      Dim NumberBytes As Int32 = 0
      Dim RetriesRemaining As Int32 = 4
      Dim Finished As Boolean = False
    
      ' Important to set up for reading response before the command is written
      ' because another thread will handle the DataReceived event and process
      ' the received data without intervention from the thread executing
      ' this(subroutine.
      m_VSP_Offset = 0
      m_WaitingOnBytes = returnLength
      ' Set the DataReceived event threshold
      m_SerialPort.ReceivedBytesThreshold = m_WaitingOnBytes - 1
      ' Set waitHandle so it will block the thread executing this routine until the data is received
      m_waitHandle.Reset()
    
      Try '  Writing
        m_SerialPort.Write(m_CommandBuffer, 0, commandLength)
      Catch exc As InvalidOperationException
        MessageBox.Show("InvalidOperationException when writing to Serial Port COM" & -1 * DeviceContext, Application.ProductName)
        ExceptionOccurred = True
      Catch exc As TimeoutException
        MessageBox.Show("TimeoutException when writing to Serial Port COM" & -1 * DeviceContext, Application.ProductName)
        ExceptionOccurred = True
      End Try
    
      If Not ExceptionOccurred Then
    
        Try ' Reading all done by Event Handler
    
          ' wait for event handler to complete its job, running in another thread
          System.Diagnostics.Debug.Print("WR_VSP: waiting on waitHandle, bytes avail: " &
                  m_SerialPort.BytesToRead & ", want bytes: " & m_WaitingOnBytes)
    
          If m_waitHandle.WaitOne(VSPtimeout) Then
            ' The WaitOne call returned True, meaning that Handle_VSP_DataReceived_Dev was able to receive all the requested data
            System.Diagnostics.Debug.Print("WR_VSP: proceeding")
          Else
            ' The WaitOne call timed out. Give it some retries before throwing an exception
            While Not Finished And RetriesRemaining > 0
              System.Threading.Thread.Sleep(VSPtimeout)
              If m_SerialPort.BytesToRead > 0 And m_SerialPort.BytesToRead >= m_WaitingOnBytes Then
                NumberBytes = m_SerialPort.Read(m_ReturnBytes, m_VSP_Offset, m_WaitingOnBytes)
                System.Diagnostics.Debug.Print("WR_VSP: timeout mode, got " & m_WaitingOnBytes & " bytes")
                Finished = True
              Else
                RetriesRemaining -= 1
              End If
            End While
            If Not Finished Then
              Throw New TimeoutException("Device failed to send the requested number of bytes.")
            End If
          End If
    
        Catch exc As InvalidOperationException
          MessageBox.Show("InvalidOperationException when reading from Serial Port COM" & -1 * DeviceContext, Application.ProductName)
          ExceptionOccurred = True
        Catch exc As TimeoutException
          MessageBox.Show("TimeoutException when reading from Serial Port COM" & -1 * DeviceContext, Application.ProductName)
          ExceptionOccurred = True
        End Try
    
      End If
    
      If ExceptionOccurred Then
        Return 1
      Else
        Return 0
      End If
    
    End Function