Designing network protocols
TCP
The main trap most people fall into while "designing" a network protocol over TCP is to assume that every "chunk" sent will be received by the program at the other end in exactly the same chunk.
This is most definitely NOT the case due to several factors:
- Packet sizes at the senders end. Chunks of data will be split into packet sizes that the network can handle.
- Buffering on the receivers end. Depending on how the client is written, packets of data will be buffered until the application is ready to receive the data. When it does, it may receive multiple complete or part packets but it will ALWAYS be in the same order it was sent.
You need to take these into account and design your protocol to have certain delimiters. Common delimiters are new lines (CR LF) or spaces and nulls. Some even used a fixed chunk size or send a header specifying the size before the main data.
Sending data
To make "nice" code, you would normally have a function that you pass a command to and it does any formatting necessary to parse it over the network connection. For this sample, I will imaginatively call it Send().
These samples are written using an imaginary Socket class and is not based around any particular library.
This code uses a simple new line as the delimiter
Sub Send(ByVal Command As String) Socket.SendData Command & vbCrLf End Sub
This code is lazy as it assumes it will be sent without a problem. Of course, when you write it, you will add error handling or check how much was actually sent and report this back to the main application.
Receiving data
When receiving data, you have no idea how you will actually receive it. To get around this, you will need to receive all data into a static buffer then perform your parsing on that.
When parsing your data, look for the first delimiter in the buffer, read any data before it and process it. You then remove this "handled" data from the buffer and repeat the process. You need to keep doing this until there is no occurrence of the delimiter in the buffer. At this point, there is either nothing left or "part" of a command waiting but is not complete so you leave it for next time.
When you next receive some data, you append it to the buffer containing the part command from the previous data and carry on as usual. This time you will find the complete command ready to be parsed.
Sub Socket_NewData(ByVal Data As String) Static Buffer As String 'This contains any data waiting to be processed Dim Command As String 'The current command as it is parsed 'Append the new data to the buffer Buffer = Buffer & Data 'Loop until no more delimiters Do While Instr(Buffer, vbCrLf) > 0 'Parse out the command before the new line Command = Mid(Buffer, 0, Instr(Buffer, vbCrLf) - 1) 'Remove the command from the buffer Buffer = Mid(Buffer, Instr(Buffer, vbCrLf) + 1) 'Do what we need to with the command ProcessCommand Command Loop End Sub
Again this code is lazy and will eventually crash if no delimiter is received. Tidying and proper error handling is left as a task to the reader. The important parts of this code are the Static variable and the loop. The static variable keep any data from one call to the next so you don't loose anything and the loop processes all the data it can so you dont get lagged.
UDP
UDP is another IP protocol and gets around this whole buffering problem although by design, the data is NOT guaranteed to arrive in the order it is sent or even at all. It is also connectionless and allows for multiple senders to be received by one receiver.
UDP is normally used for streaming video/audio protocols where the extra error checking and connection is too much of an overhead and there is no need for the reliability.