Creating communication protocol over TCP Sockets?
I have an Arduino microcontroller with a Sparkfun WiFly shield.
I build a simple program in C#/.NET that connects to the Arduino using System.Net.Sockets
:
Socket Soc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
public void SendMsg(string msg)
{
try
{
byte[] buffer = StrToByteArray(msg);
if (Soc.Connected)
Soc.Send(buffer);
开发者_运维百科 else
{
Soc.Connect(this.remoteIP);
Soc.Send(buffer);
}
}
catch (Exception e){}
}
On the arduino I have:
while(SpiSerial.available() > 0) {
byte b = SpiSerial.read();
Serial.println(b);
}
When a socket connection does a handshake, I get: "*OPEN*" and when closed, I get: "*CLOS*".
The problem is that I get the messages one byte by another and sometimes I don't get the full message on one while
loop.
So if I use the code I showed above on the Arduino, my serial terminal looks like:
*
O
P
E
N
*
T
E
S
T
*
C
L
O
S
*
So how can I figure out the message the PC is trying to send?
I know I need somehow to use a special byte that will symbolise the end of my message. (A special byte that I won't use in my message, only to symbolise the end of a message)
But how can I do it? And which byte to use?
You need to design your own protocol here. You should define a byte (preferably one that won't occur in the data) to indicate "start", and then you have three choices:
- follow the start byte with a "length" byte indicating how much data to read
- define an "end" byte that marks the end of your data
- read data until you have a complete message that matches one of the ones you expect
The third option is the least extensible and flexible, of course, as if you already have a message "OPEN" you can't then add a new message "OPENED" for instance.
If you take the second option and define an "end" byte then you need to worry about escaping that byte if it occurs within your data (or use another byte that is guaranteed not to be in your data).
Looking at your current example, a good starting point would be to simply prefix each message with a length prefix.
If you want to support long messages you can use a 2 byte length prefix, then you read the first 2 bytes to get the length and then you continue reading from the socket until you have read the number of bytes indicated by the length prefix.
Once you have read a complete message you are then back to expecting to read the length prefix for the next message and so on until the communication is terminated by one of the parties.
Of course in between all this you need to check for error conditions like the socket on one end being closed prematurely etc. and how to handle the potential partial messages that can result form the premature closing of the socket.
精彩评论