TcpClient maximum packet size for sending data - vb.net

I am building a communication library based on the Net.Sockets.TcpClient class. During some unit tests I wanted to test how large a datapacket could be before running into problems. My theory was that the actual size would not matter because the TcpClient would split the data into parts because of its internal sendbuffer. But the actual size did matter because somewhere around 600KB I discovered loss of data.
What my test does is create a local server and a local client that connect with each other. Then it sends a specific (large) package in a loop to test if the server receives it well. I left out all checks but after sending the data a check runs that the data is exactly the same as what was send before looping again. So there is never more data in the pipe than the size that I specified. This code is the client part in my unit test. The server part is a whole library so I cannot post that.
Using myClient As New Net.Sockets.TcpClient()
myClient.BeginConnect("127.0.0.1", ServerPort, Nothing, Nothing)
'Code that checks if the connection has been made
'Create a large string
Dim SendString as String = StrDup(1024000, "A")
Dim SendBytes as Byte() = Text.Encoding.ASCII.GetBytes(SendString)
'Loop the test
For i As Int32 = 1 To 10000
Wait.Reset()
myClient.Client.Send(SendBytes)
Wait.WaitOne(10000) 'Wait for the server to acknowledge
'Run checks to make sure the data is good, otherwise end loop
Next
myClient.Close()
End Using
What happens is that at some random point the server does not receive all data. It looks like sending 1.024.000 bytes of data works most of the times but not always. The iteration at which it fails is random but a loop will never finish 10.000 iterations successfully. I tested the loop with 512.000 bytes and that works. I also tested 600.000 bytes and that failed. I do not know what the actual size is at which it starts failing because it does not seem to be a hard limit. I cannot figure out the problem. Is the TcpClient somehow limited or do I exceed an internal buffer of some kind? I checked the SendBufferSize of the TcpClient and it was 65536. I have no idea if that has anything to do with it. Packages larger than that buffer seem to be sending just fine.

Related

Serializing Multiple Objects into ByteArray

I am wondering one thing; How can I serialize multiple objects to a byte array. My goal is to send the serialized object over tcp, receive it, then deserialize it, and recreate it.
My concept is:
The first thing in the byte array will be the "Packet Header" -- This will tell the receiver what type of packet it is; "Chat Message", "File Transfer", etc etc. Then after the header I will add the packet itself. Then at last there will be an "EOF Header" (This will tell the server if the whole packet is received). - The headers are enumerables(as Byte).
where you get these errors would be helpful (essential even) but it is probably related to this:
Public Shared Function Deserialize(Data As Byte()) As Packet
Dim MS As New MemoryStream(Data)
Dim BF As New BinaryFormatter
MS.Position = 0
' or
'MS.Seek(0, SeekOrigin.Begin)
Return DirectCast(BF.Deserialize(MS), Packet)
End Function
After seeding the memstream, the stream position is left at the end. You need to reset it so the BF can read all the bytes. (and you really dont need things like BOF and EOF in the serialized data - even if you are sending multiple things, if you put them in a list, they will either de/serialize in toto or not).
Also look at ProtoBuf-NET - much faster serializer making much smaller packets, and it will let you deserialize into a different assembly-culture-class which NET's BF does not do without basically tricking it.

How Can I Tell If Another Message Is Pending In A TCP Connection

I have a sending application that uses TCP to send files. Sometimes these files contain one message, and other times the file may contain multiple messages. Unfortunately, I do not have access to the Sending application's code.
I am working on editing legacy code to receive these messages. I have managed to get the legacy application to accept a file when there is a single message sent. However, since I disconnect the socket after receiving a single message, the Sender gives a disconnect error.
I wrote a small process to help determine whether there was another message. If it worked, I was going to incorporate it into the code, but I had mixed results:
Dim check(1) As Byte
If (handler.Receive(check, SocketFlags.Peek) > 0) Then
Dim bytesRec As Integer
ReDim bytes(1024)
bytesRec = handler.Receive(bytes)
End If
If there is another message being sent, this will detect it. However, if the file only has a single message, it locks up on Receive until I send another file, and then it is accepted.
Is there a way to tell if there is another message pending that will not lock up if the stream is empty?
I won't post all of the code for accepting the message, as it is a legacy rat's nest, but the general idea is below:
s2 = CType(ar.AsyncState, Socket)
handler = s2.EndAccept(ar)
bytes = New Byte(1024) {}
Dim bytesRec As Integer = handler.Receive(bytes)
' Send Ack/Nak.
numAckBytesSent = handler.Send(myByte)
Thank you in advance for any assistance.
Socket.Select can be used as a quick way of polling a socket for readability. Pass in a timeout of 0 seconds, and the socket in question in the readability list, and it will simply check and report back immediately.
Two other options might be to set Socket.ReceiveTimeout on your socket, or make the socket non-blocking using Socket.Blocking, so that you can find out (as part of the Receive call) whether there is incoming data. These look a bit inconvenient to do in .NET, though, as they throw exceptions rather than simply returning a value, which might make the code a little longer.
Just keep reading. If there is nothing left you will get an end-of-stream indication of some kind, depending on your API.

VB .net get the client connection params of the socket on server side

I want both the client and server to write and read resp. at a constant rate (which can be configured on the GUI of the client) to the buffer.
Say,
I am able to send from the client at 150 bytes per packet
Now, I should be able to read also at 150 bytes per packet on the server too
Since, both are connected through a socket, can we retrieve the socket params (set on the client size, like 150 here) from the server end, using the tcpServer object.
Or is it must to send an initial setup packet which tells about these client params and so accordingly the server can continue?
It's kinda usual to sort message sizes out at the application level. You could indeed send a 'setup message' as the first data after a successful connect. You should send this setup message in a form that will not be misunderstood due to endianness or the number of bytes received per read call. Perhaps a fixed-size messge in ASCII, maybe five bytes:
'00150'
The server can then read five bytes only, convert to integer, save it in the server-client socket object so that the server always knows how many bytes to send and then issue a read call for that number of bytes.
Alternatively, you could use a simple protocol that embeds the size into each message, eg:
SOH
"0"
"0"
"1"
"5"
"0"
[150 bytes of data]
EOT
Rgds,
Martin

Socket programming VB.NET - Read blocks indefinitely

Following is the code that I'm using for reading data over a .NET socket. This piece of code is run by a single separate thread. It works OK the first time, on the second iteration it stops at "client.Receive(buffer)" and never recovers from it. Initially I was using recursion to read data but changed it to iteration thinking that recursion could be the source of problem. But apparently it is not.
Private Sub ReceiveSocket(ByVal client As Socket)
Dim bytesRead As Integer = 0
Do
bytesRead = client.Receive(buffer)
sb.Append(Encoding.ASCII.GetString(buffer, 0, bytesRead))
Array.Clear(buffer, 0, buffer.Length)
Loop While bytesRead > 0
End Sub 'ReceiveCallback
Why does it hang at Receive?
Well, that's normal. The Receive() method won't return until the server sends something else. Which it probably doesn't do in your case until you ask it to send something else first. You should only call Receive() again if you didn't get the full server response.
Check the protocol specification. A server usually sends something that lets you tell that the full response was received. Like the number of bytes in the message. Or a special character at the end of the message. Linefeed (vbLf) is popular.

How do i start Process iteratively in VB.NET? or change argument dynamically

i have used following code to repeat a process creation/close iteratively
dim vProcessInfo as new ProcessInfo
For i= 1 to 100
dim p as new Process
vProcessInfo.Arguments = "some"+i.toString()
p.StartInfo = vProcessInfo
p.Start()
p.WaitForExit()
p.Close()
Next i
the above code worked for me successfully. but it takes too much time for process creation and dispose. i had to change process argument dynamically in the iteration. is there any way to change the process argument dynamically. or is there any better method to reduce time. pls help me
"Is there any way to change the process argument dynamically" - do you mean you want to start one process, and change its command line arguments after it's started? No, you can't do that - but you could communicate with it in other ways, for example:
Using standard input/output (e.g. write lines of text to its standard input)
Using files (e.g. you write to a file, it monitors the directory, picks up the file and processes it)
Using named pipes or sockets
Creating a process is a relatively slow operation. You can't easily speed that up - but if you can change your process in some way like the above, and just launch it once, that should make it a lot faster.