Asked by:
Asynchronous Operator | TCP | Serialization

Question
-
Hello dear Sirs,
I need your help to make my server and client asynch.
Here is the code
Dll to serialize :
Public Class Class1 <Serializable()> Public Class PacketMaker Public Property File As Byte() Public Property Type_Packet As PacketType End Class Public Enum PacketType As Integer MSG = &H5057 File = &H5056 End Enum End Class
Server :
Imports System.Net Imports System.Net.Sockets Imports System.Runtime.Serialization.Formatters.Binary Imports System.Text Imports System.Threading Imports ClassLibrary1.Class1 Public Class Form1 Public T As TcpListener = New TcpListener(IPAddress.Any, 8080) Private client As TcpClient Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click T.Start() Task.Run(Sub() D()) End Sub Public Sub D() While True client = T.AcceptTcpClient() Task.Run(Sub() ThreadProc2(client)) Task.Run(Sub() ThreadProc(client)) End While End Sub Private Sub ThreadProc(ByVal obj As Object) Dim client = CType(obj, TcpClient) Dim B As BinaryFormatter = New BinaryFormatter() Dim p As PacketMaker = New PacketMaker() p.Type_Packet = PacketType.MSG p.File = IO.File.ReadAllBytes("File1.zip") B.Serialize(client.GetStream(), p) End Sub Private Sub ThreadProc2(ByVal obj As Object) Dim client = CType(obj, TcpClient) Dim B As BinaryFormatter = New BinaryFormatter() Dim p As PacketMaker = New PacketMaker() p.Type_Packet = PacketType.File p.File = IO.File.ReadAllBytes("File2.zip") B.Serialize(client.GetStream(), p) End Sub End Class
Client :
Imports System.Net Imports System.Net.Sockets Imports System.Runtime.Serialization.Formatters.Binary Imports ClassLibrary1.Class1 Public Class Form1 Private T As TcpClient = New TcpClient() Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim address As String = "192.168.0.15" T.Connect(IPAddress.Parse(address), 8080) Dim N As NetworkStream = T.GetStream() Task.Run(Sub() R(N)) End Sub Public Sub R(ByVal L As NetworkStream) Dim sf As BinaryFormatter = New BinaryFormatter() While True Dim po As PacketMaker = CType(sf.Deserialize(L), PacketMaker) IO.File.WriteAllBytes(po.Type_Packet.ToString(), po.File) End While End Sub End Class
The server send 2 files and client need to receive them but here nothing is happening. No file is written (MSG & FILE). The only way to avoid problem I have found is to set a synclock here :
Private Sub ThreadProc(ByVal obj As Object) SyncLock T Dim client = CType(obj, TcpClient) Dim B As BinaryFormatter = New BinaryFormatter() Dim p As PacketMaker = New PacketMaker() p.Type_Packet = PacketType.MSG p.File = IO.File.ReadAllBytes("File1.zip") B.Serialize(client.GetStream(), p) End SyncLock End Sub Private Sub ThreadProc2(ByVal obj As Object) SyncLock T Dim client = CType(obj, TcpClient) Dim B As BinaryFormatter = New BinaryFormatter() Dim p As PacketMaker = New PacketMaker() p.Type_Packet = PacketType.File p.File = IO.File.ReadAllBytes("File2.zip") B.Serialize(client.GetStream(), p) End SyncLock End Sub
- Edited by Arsium Thursday, November 26, 2020 2:49 PM
Thursday, November 26, 2020 2:34 PM
All replies
-
Hello,
The following are suggestions, incomplete but are solid ideas to use with asynchronous operations. Don't have time to write up a code sample.
Make sure to read the following to get a handle on this type of coding.
Consider using the following where the method need to be marked with Async
Dim client As TcpClient = Await listener.AcceptTcpClientAsync()
I'd use a function e.g.
Public Async Function Run() As Task
And it may be beneficial to have a way to cancel the operation
Public Async Function Run(ByVal cancellationToken As CancellationToken) As Task
Finally consider using a TraceListener to log operations, I have a simple/basic example here.
Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
NuGet BaseConnectionLibrary for database connections.
My GitHub code samples
GitHub pageCheck out: the new Microsoft Q&A forums
- Proposed as answer by KHURRAM RAHIM Friday, November 27, 2020 10:59 AM
- Unproposed as answer by Arsium Friday, November 27, 2020 11:33 AM
Thursday, November 26, 2020 4:06 PM -
So according to : Asynchronous Programming with Async and Await - Visual Basic | Microsoft Docs I can't use TcpClient | Listener Async with binaryformatter and serialization ?Thursday, November 26, 2020 9:13 PM
-
Hi Arsium,
We’re doing research on this issue. It might take some time before we get back to you.
Thank you for your patience
Best Regards,
Xingyu Zhao
Visual Basic and CLR forum will be migrating to a new home on Microsoft Q&A! (VB.NET and CLR) We invite you to post new questions in the new home on Microsoft Q&A ! For more information, please refer to the sticky post(VB.NET and CLR).
Friday, November 27, 2020 9:27 AM -
Okay okay no problem hope you will find an idea / solutionSaturday, November 28, 2020 11:43 AM
-
Hi Arsium,
Did you consider using asynchronous socket?
Here are two related references you can refer to.
Besides, here's an example of asynchronous tcp server you may need.
Private Async Sub button1_Click(ByVal sender As Object, ByVal e As EventArgs) Await Task.Run(Sub() RunServerAsync()) End Sub Private Async Sub RunServerAsync() Dim listener = New TcpListener(IPAddress.Any, 8080) listener.Start() Try While True Await Accept(Await listener.AcceptTcpClientAsync()) End While Finally listener.Stop() End Try End Sub Private Async Function Accept(ByVal client As TcpClient) As Task Await Task.Yield() Try Using client Using n As NetworkStream = client.GetStream() Dim send_data As Byte() Dim bf As BinaryFormatter = New BinaryFormatter() Using ms = New MemoryStream() bf.Serialize(ms, yourObject) send_data = ms.ToArray() End Using Await n.WriteAsync(send_data, 0, send_data.Length) End Using End Using Catch ex As Exception Console.WriteLine(ex.Message) End Try End Function
Best Regards,
Xingyu Zhao
Visual Basic and CLR forum will be migrating to a new home on Microsoft Q&A! (VB.NET and CLR) We invite you to post new questions in the new home on Microsoft Q&A ! For more information, please refer to the sticky post(VB.NET and CLR).
- Edited by Xingyu ZhaoMicrosoft contingent staff Tuesday, December 1, 2020 9:16 AM
Tuesday, December 1, 2020 9:15 AM -
Okay okay I misspoke my request : is it possible to serialize in parallel (not async) while using binaryformatter and network stream ?
- Edited by Arsium Tuesday, December 1, 2020 8:40 PM
Tuesday, December 1, 2020 10:30 AM -
Okay okay I misspoke my request : is it possible to serialize in parallel (not async) while using binaryformatter and network stream ? This causes my problem (not async) I'm beginner sry
Tuesday, December 1, 2020 8:40 PM -
Hi Arsium,
>>is it possible to serialize in parallel (not async) while using binaryformatter and network stream ?
Yes, when you send multiple messages using TCP, you need to split the message at the other end in some way.
As you can see in the following code, I save each length of the message to byte array with a fixed length of 4.
Server:
Public Class Form1 Private port As Integer = 8080 Private _running As Boolean Private listener As TcpListener Private connectedTcpClient As TcpClient Private _bFormatter As BinaryFormatter = New BinaryFormatter() Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load listener = New TcpListener(IPAddress.Any, port) End Sub Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click If Not _running Then listener.Start() Me._running = True Task.Factory.StartNew(Sub() ListenForClientConnections() End Sub) End If End Sub Private Sub ListenForClientConnections() While Me._running Me.connectedTcpClient = listener.AcceptTcpClient() Dim networkStream As NetworkStream = Me.connectedTcpClient.GetStream() Dim p As PacketMaker = New PacketMaker() p.Type_Packet = PacketType.MSG p.File = File.ReadAllBytes("D:\test.txt") 'File1.zip Dim p2 As PacketMaker = New PacketMaker() p2.Type_Packet = PacketType.File p2.File = File.ReadAllBytes("D:\test2.txt") 'File2.zip SendMessage(_bFormatter, networkStream, p) SendMessage(_bFormatter, networkStream, p2) End While End Sub Private Sub SendMessage(ByVal _bFormatter As BinaryFormatter, ByVal networkStream As NetworkStream, ByVal p As PacketMaker) Dim header As Byte() = New Byte(3) {} Dim send_dataLen As Integer = 0 Dim send_data As Byte() Using ms = New MemoryStream() _bFormatter.Serialize(ms, p) send_data = ms.ToArray() send_dataLen = ms.ToArray().Length End Using ' Convert the integer type length value to byte array and then send it. header = convertToByteArray(header, send_dataLen) networkStream.Write(header, 0, header.Length) networkStream.Write(send_data, 0, send_data.Length) End Sub Private Function convertToByteArray(ByVal header As Byte(), ByVal i As Integer) As Byte() Dim swi As Switcher = New Switcher() swi.intVal = i header(0) = swi.b0 header(1) = swi.b1 header(2) = swi.b2 header(3) = swi.b3 Return header End Function Public Sub StopListen() If Me._running Then listener.Stop() Me._running = False End If End Sub End Class <StructLayout(LayoutKind.Explicit)> Structure Switcher <FieldOffset(0)> Public intVal As Integer <FieldOffset(0)> Public b0 As Byte <FieldOffset(1)> Public b1 As Byte <FieldOffset(2)> Public b2 As Byte <FieldOffset(3)> Public b3 As Byte End Structure
Client:
Private address As String = "your ip address" Private port As Integer = 8080 Private client As TcpClient = New TcpClient() Private _bFormatter As BinaryFormatter = New BinaryFormatter() Private _running As Boolean Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click client.Connect(IPAddress.Parse(address), port) StartListening() End Sub Public Sub StartListening() SyncLock Me If Not _running Then Me._running = True Task.Factory.StartNew(Sub() ListenForMessage() End Sub) Else Me._running = True Task.Factory.StartNew(Sub() ListenForMessage() End Sub) End If End SyncLock End Sub Private Sub ListenForMessage() While Me._running Dim networkStream As NetworkStream = client.GetStream() Dim header As Byte() = New Byte(3) {} Dim receive_data As Byte() = New Byte(65534) {} Dim packageLen As Integer = 0 Dim offset As Integer = 0 Dim bytesRead As Integer = networkStream.Read(receive_data, 0, receive_data.Length) Dim count As Integer = 3 While bytesRead <> 0 AndAlso bytesRead > offset Using ms = New MemoryStream() ms.Write(receive_data, offset, 4) header = ms.ToArray() ' Convert length of message byte array to the integer packageLen = BitConverter.ToInt32(header, 0) ms.Seek(0, SeekOrigin.Begin) ms.Write(receive_data, offset + 4, packageLen) ms.Seek(0, SeekOrigin.Begin) Dim po As PacketMaker = CType(_bFormatter.Deserialize(ms), PacketMaker) File.WriteAllBytes("D:\test" & count & ".txt", po.File) count += 1 End Using offset += packageLen + 4 End While End While End Sub
I use two txt files to make the test.
Content in two files.
Result of my test.
Hope it could be helpful.
Best Regards,
Xingyu Zhao
Visual Basic and CLR forum will be migrating to a new home on Microsoft Q&A! (VB.NET and CLR) We invite you to post new questions in the new home on Microsoft Q&A ! For more information, please refer to the sticky post(VB.NET and CLR).
- Edited by Xingyu ZhaoMicrosoft contingent staff Wednesday, December 2, 2020 9:59 AM
Wednesday, December 2, 2020 9:54 AM -
Okay okay thx I will try that !Thursday, December 3, 2020 5:42 PM
-
Hello Sir ,
I've tried your code and nothing is happening with those sent files...I tried with 200MB for first file and 8MB for second and nothing happened. However , it seems working with low size files.
- Edited by Arsium Saturday, December 5, 2020 12:23 PM
Saturday, December 5, 2020 12:09 PM