From bf77505f4231e35585846547c6d355643e406018 Mon Sep 17 00:00:00 2001 From: schedpas Date: Tue, 9 Jun 2020 09:35:06 +0200 Subject: [PATCH] automaticly send large data as packages --- Pilz.Networking/ConnectionManagerBase.vb | 122 +++++++++++++++++++---- Pilz.Networking/TCPManager.vb | 7 +- Pilz.Networking/UDPManager.vb | 9 +- 3 files changed, 112 insertions(+), 26 deletions(-) diff --git a/Pilz.Networking/ConnectionManagerBase.vb b/Pilz.Networking/ConnectionManagerBase.vb index c3b4e7d..1f1dc1d 100644 --- a/Pilz.Networking/ConnectionManagerBase.vb +++ b/Pilz.Networking/ConnectionManagerBase.vb @@ -4,7 +4,10 @@ Imports Newtonsoft.Json.Linq Public MustInherit Class ConnectionManagerBase + Private Const HEADER_LENGTH As Integer = 12 + Private listening As Boolean = False + Private ReadOnly dicData As New Dictionary(Of Integer, Dictionary(Of Integer, Byte())) Public ReadOnly Property Port As Integer Public Property UseAssemblyQualifiedName As Boolean = False @@ -31,6 +34,7 @@ Public MustInherit Class ConnectionManagerBase Public MustOverride Sub Start() Public MustOverride Sub [Stop]() Protected MustOverride Sub SendData(endPoint As IPEndPoint, data As Byte()) + Protected MustOverride Function GetBufferSize() As Integer Public Overridable Sub Send(empfängerIP As String, cmd As String) Send(empfängerIP, cmd, String.Empty) @@ -45,21 +49,108 @@ Public MustInherit Class ConnectionManagerBase End Sub Protected Sub ProcessRetrivedData(senderIP As String, buf As Byte()) - Dim contentstring As String = Text.Encoding.Default.GetString(buf) - Dim content As Object = Nothing - Dim cmd As String = String.Empty + Dim readInteger = + Function(index As Integer) As Integer + Return (CInt(buf(index)) << 24) Or (CInt(buf(index + 1)) << 16) Or (CInt(buf(index + 2)) << 8) Or buf(index + 3) + End Function - Try - Dim res = DecodeFromBytes(buf) - cmd = res.cmd - content = res.content - Catch ex As Exception - End Try + Dim dataID As Integer = readInteger(0) + Dim packageID As Integer = readInteger(4) + Dim packageCount As Integer = readInteger(8) + Dim resolveData As Boolean = True - RaiseRetriveData(senderIP, cmd, content) + 'Remember data + Dim data As Byte() = buf.Skip(HEADER_LENGTH).ToArray + Dim dicMyData As Dictionary(Of Integer, Byte()) + + If dicData.ContainsKey(dataID) Then + dicMyData = dicData(dataID) + If dicMyData.ContainsKey(packageID) Then + dicMyData(packageID) = data + Else + dicMyData.Add(packageID, data) + End If + Else + dicMyData = New Dictionary(Of Integer, Byte()) From {{packageID, data}} + dicData.Add(dataID, dicMyData) + End If + + If dicMyData.Count < packageCount Then + resolveData = False + End If + + 'Resolve Data + If resolveData Then + If dicMyData Is Nothing Then + dicMyData = dicData(dataID) + End If + Dim myData As New List(Of Byte) + For Each kvp In dicMyData.OrderBy(Function(n) n.Key) + myData.AddRange(kvp.Value) + Next + dicMyData.Remove(dataID) + + Dim content As Object = Nothing + Dim cmd As String = String.Empty + Try + Dim res = DecodeFromBytes(myData.ToArray) + cmd = res.cmd + content = res.content + Catch ex As Exception + End Try + + RaiseRetriveData(senderIP, cmd, content) + End If End Sub - Protected Shared Function EncodeToBytes(cmd As String, content As Object, useAssemblyQualifiedName As Boolean) As Byte() + Public Sub Send(empfängerIP As String, cmd As String, content As Object) + Static rnd As New Random + Dim ep As New IPEndPoint(GetIPFromHost(empfängerIP).MapToIPv4, Port) + Dim finalBuffer As New List(Of Byte) + Dim maxBufferSize As Integer = GetBufferSize() + Dim maxDataSize As Integer = maxBufferSize - HEADER_LENGTH + Dim data As Byte() = EncodeToBytes(cmd, content, UseAssemblyQualifiedName) + Dim dataID As Integer = rnd.Next + + 'Some methods for later user + Dim send = Sub() SendData(ep, finalBuffer.ToArray) + Dim addInteger = + Sub(value As Integer) + finalBuffer.AddRange({(value >> 24) And &HFF, (value >> 16) And &HFF, (value >> 8) And &HFF, value And &HFF}) + End Sub + Dim addHeader = + Sub(packageID As Integer, packagesCount As Integer) + addInteger(dataID) 'Data ID + addInteger(packageID) 'Package ID + addInteger(packagesCount) 'Packages Count + End Sub + + 'Send data (this if statement and else content might be useless) + If data.Length > maxDataSize Then + Dim curIndex As Integer = 0 + Dim curID As Integer = 0 + Dim packagesCount As Integer = Math.Ceiling(data.Length / maxDataSize) + + Do While curIndex < data.Length + finalBuffer.Clear() + addHeader(curID, packagesCount) + For i As Integer = 1 To maxDataSize + If curIndex < data.Length Then + finalBuffer.Add(data(curIndex)) + curIndex += 1 + End If + Next + send() + curID += 1 + Loop + Else + addHeader(0, 1) + finalBuffer.AddRange(data) + send() + End If + End Sub + + Private Shared Function EncodeToBytes(cmd As String, content As Object, useAssemblyQualifiedName As Boolean) As Byte() Dim ms As New MemoryStream() Dim bw As New BinaryWriter(ms) Dim obj As New JObject @@ -81,7 +172,7 @@ Public MustInherit Class ConnectionManagerBase Return buf End Function - Protected Shared Function DecodeFromBytes(buf As Byte()) As (cmd As String, content As Object) + Private Shared Function DecodeFromBytes(buf As Byte()) As (cmd As String, content As Object) Dim contentstring As String = Text.Encoding.Default.GetString(buf) Dim content As Object = Nothing Dim contentobj As JObject = JObject.Parse(contentstring) @@ -98,11 +189,4 @@ Public MustInherit Class ConnectionManagerBase Return (cmd, content) End Function - Public Sub Send(empfängerIP As String, cmd As String, content As Object) - Dim ep As New IPEndPoint(GetIPFromHost(empfängerIP).MapToIPv4, Port) - Dim buf As Byte() = EncodeToBytes(cmd, content, UseAssemblyQualifiedName) - - SendData(ep, buf) - End Sub - End Class diff --git a/Pilz.Networking/TCPManager.vb b/Pilz.Networking/TCPManager.vb index bbe1fb3..801dcf9 100644 --- a/Pilz.Networking/TCPManager.vb +++ b/Pilz.Networking/TCPManager.vb @@ -23,9 +23,6 @@ Public Class TCPManager End If End Sub - ''' - ''' Stop listening on given port. - ''' Public Overrides Sub [Stop]() If IsListening Then IsListening = False @@ -33,6 +30,10 @@ Public Class TCPManager End If End Sub + Protected Overrides Function GetBufferSize() As Integer + Return BufferSize + End Function + Private Sub CheckRetriveData() Do While IsListening If listener.Pending Then diff --git a/Pilz.Networking/UDPManager.vb b/Pilz.Networking/UDPManager.vb index 42ea9c6..99dba2e 100644 --- a/Pilz.Networking/UDPManager.vb +++ b/Pilz.Networking/UDPManager.vb @@ -12,7 +12,7 @@ Public Class UDPManager Private listenTask As Task = Nothing Private ReadOnly cancelTokenSource As New CancellationTokenSource Private ReadOnly cancelToken As CancellationToken = cancelTokenSource.Token - Public ReadOnly Property MaxBufferSize As Integer = &H10000 + Public ReadOnly Property MaxBufferSize As Integer = 8192 Public Sub New(port As Integer) MyBase.New(port) @@ -43,9 +43,6 @@ Public Class UDPManager End Sub) End Sub - ''' - ''' Stop listening on given port. - ''' Public Overrides Sub [Stop]() If IsListening Then IsListening = False @@ -54,6 +51,10 @@ Public Class UDPManager End If End Sub + Protected Overrides Function GetBufferSize() As Integer + Return MaxBufferSize + End Function + Private Sub RetriveAnyData(ct As CancellationToken) Dim doExit = Sub() ct.ThrowIfCancellationRequested() Dim receiveTask As Task(Of UdpReceiveResult) = client.ReceiveAsync()