作为(希望)所有开发人员,我多年来一直在开发,现在正处于OOP和函数式编程的日常成本之中。最近我碰到了老了" (2年)我读取TCP流的DLL,将传入的字符串(以换行符结尾)放入ConcurrentQueue(Of String)。然后第二个Backgroundworker遍历ConcurrentQueue(Of String)并将字符串出列并解析它。
根据我发送给TCP服务器的请求命令,我得到一行或几行。此外,当没有任何要求时,TCP服务器什么都不发送。这完全是事件驱动的。
随着新的高效技术PLINQ,Async / Await和TPL,我决定让它更快/更高效。目前我正在集思广益,如何做到这一点,并要求你和我一起思考或给出一些好的建议。
让我们深入了解我现在拥有的东西: 它首先从两个背景工作者开始,一个用于阅读,一个用于解析。
阅读背景工作者: 这个后台工作者的工作是读取输入数据,并确保继续阅读,直到换行通过。然后它切成一个字符串并将其放入ConcurrentQueue(Of String)。代码如下所示:
Private Sub bgwReceive_DoWork(sender As Object, e As DoWorkEventArgs) Handles bgwTCP_Receive.DoWork
Dim strRXData As String = String.Empty
Dim intLfpos As Integer = 0
Try
Do Until bgwTCP_Receive.CancellationPending
'while the client is connected, continue to wait for and read data
While _Client.Connected AndAlso _ClientStream.CanRead
Dim buffer(_Client.ReceiveBufferSize - 1) As Byte
Dim read As Integer = _ClientStream.Read(buffer, 0, buffer.Length)
'Put the new data in the queue
If read > 0 Then
'Add incomming data to the buffer string
strRXData &= Text.Encoding.ASCII.GetString(buffer, 0, read)
'Replace "0 padding"
strRXData.Replace(Chr(0), String.Empty)
'Now check if we have a Linefeed in our buffer string
While strRXData <> String.Empty
'Get the position of the first linefeed
intLfpos = strRXData.IndexOf(vbLf)
'Now check if we find something.
If intLfpos < 0 Then Exit While
'There is a line feed, it is time to add it to the incomming data queue
IncommingData.Enqueue(strRXData.Substring(0, intLfpos - 1))
'Now remove the command from the buffer string
strRXData = strRXData.Substring(intLfpos + 1, strRXData.Length - intLfpos - 1)
End While
End If
'Check if we have to stop
If bgwTCP_Receive.CancellationPending Then e.Cancel = True : Exit Do
Threading.Thread.Sleep(1)
End While
Threading.Thread.Sleep(100)
Loop
e.Cancel = True
Catch op As OperationCanceledException
Throw New Exception("TCP Reading cancelled")
Catch se As SocketException
Throw New Exception("Socket unknown error. Native error code: " & se.NativeErrorCode)
Catch IOex As IOException
Throw New Exception("Socket timeout while receiving data from [" & TCP_ServerIP.ToString & "]")
End Try
End Sub
Parsing Backgroundworker:这个backgroundworker工作是解析ConcurrentQueue(Of String)中的字符串。在这个背景工作者中,有一个大的Select案例,它会查看字符串中的第一个单词。这决定了该怎么做。
收到的协议非常简单,但不幸的是它没有像JSON这样的索引结构。字符串看起来像这样:IND PARM1:&#34; Hello world!&#34; PARM2:1.4.8 \ CrLf
正如您所看到的,它非常简单明了。 IND表示命令,如VER用于VERSION字符串。 IND总是3个字符长。然后是参数。参数名称总是4个字符长。如果它在双引号之间,它是一个字符串,否则它就像一个双/整数/ IP地址(X.X.X.X)。请记住原始它是一个字符串。在我的解析器中,我将其解析为对象属性。代码如下所示:
Private Sub bgwProcessQueue_DoWork(sender As Object, e As DoWorkEventArgs) Handles bgwProcessQueue.DoWork
Dim strNewLine As String = String.Empty
Dim strSubLine As String = String.Empty
Try
'Loop until program has stopped
Do Until bgwProcessQueue.CancellationPending
'Only process when something is in the queue
If TCP_Connection.IncommingData.TryDequeue(strNewLine) Then
'If Backgroundworker has to cancel than cancel
If bgwProcessQueue.CancellationPending Then Exit Do
Select Case True
Case strNewLine.StartsWith("VER") 'Example: VER PRM1:1.1 PRM2:"Hi there" PRM3:1.1.1 PRM4:8/0 PRM5:8
'First check if all the needed values are there, if not resend the command
If strNewLine.Contains("PRM1:") AndAlso strNewLine.Contains("PRM2:") AndAlso strNewLine.Contains("PRM3:") AndAlso strNewLine.Contains("PRM4:") AndAlso strNewLine.Contains("PRM5:") Then
'Get versions and devicename
Me.Param1 = GetSubstring(strNewLine, "PRM1:", " ")
Me.Param2 = GetSubstring(strNewLine, "PRM2:", " ")
Me.Param3 = GetSubstring(strNewLine, "PRM3:", " ")
Me.Param4 = GetSubstring(strNewLine, "PRM4:", " ")
Me.Param5 = GetSubstring(strNewLine, "PRM5:", " ")
Else
'Commando was invalid, resend the command
Log.Message(LogLevel.Warning, "VER Messages was incompleet, resending VER command")
SendData("VER")
End If
Case strNewLine.StartsWith("ERROR")
Log.Message(LogLevel.Warning, strNewLine)
End Select
End If
'Clear any old data
strNewLine = String.Empty
'Sleep
Threading.Thread.Sleep(1)
Loop
e.Cancel = True
Catch ex As Exception
Log.Exception(ex)
End Try
End Sub
Private Function GetSubstring(text As String, StartValue As String, EndValue As String) As String
Try
'If we can't find the Start value we can't do anything
If Not text.Contains(StartValue) Then Return String.Empty
'Find the index of the Start and End value
intStartValueIndex = text.IndexOf(StartValue) + StartValue.Length
intEndValueIndex = text.IndexOf(EndValue, intStartValueIndex)
'If no Endvalue index was found then get the end of the string
If intEndValueIndex < intStartValueIndex Then intEndValueIndex = text.Length
'Return the substring en remove quetes
Return text.Substring(intStartValueIndex, intEndValueIndex - intStartValueIndex).Replace("""", "")
Catch ex As Exception
Log.Exception(ex)
Return String.Empty
End Try
End Function
希望以上所有内容都是可以理解的。我正在考虑使用Parrallel.ForEach循环遍历ConcurrentQueue(Of String),并将Dequeued字符串传递给执行解析的sub。在阅读方面,我的灵感目前是空的......