jmasterx
jmasterx

Reputation: 54113

Changing this protocol to work with TCP streaming

I made a simple protocol for my game:

b = bool
i = int
sINT: = string whose length is INT followed by a : then the string
m = int message id.

Example:

m133s11:Hello Worldi-57989b0b1b0

This would be:

Message ID 133
String 'Hello World' length 11
int -57989
bool false
bool true
bool false

I did not know however that TCP could potentially only send PART of a message. I'm not sure exactly how I could modify this such that I can do the following:

on receive data from client:
use client's chunk parser
process data
if has partial message then try to find matching END
if no partial messages then try to read a whole message

for each complete message in queue, dispatch it

I could do this by adding B at the beginning of a message and E at the end, then parsing through for the first char to be B and last to be E.

The only problem is what if I receive something silly in the middle that does not follow the protocol. Or, what if I was supposed to just receive something that is not a message and is just a string. So if I was somehow intended to receive the string HelloB, then I would parse this as hello and the beginning of a message, but I would never receive that message because it is not a message.

How could I modify my protocol to solve these potential issues? As much as I anticipate only ever receiving correctly formed messages, it would be a nightmare if one was poorly encoded and set everything out of whack.

Thanks

I decided to add the length at the beginning and keep track of if I'm working on a message or not: so:

p32m133s11:Hello Worldi-57989b0b1b0

I then have 3 states, reading to find 'p', reading to find the length after 'p' or reading bytes until length bytes have been read.

What do you think?

It seems to work great.

Upvotes: 0

Views: 160

Answers (1)

Ben
Ben

Reputation: 35613

What you are doing is pretty old-school, magnetic tape stuff. Nice.

The issue you might have is that if a part of the message is received, you cannot tell if you are partway through a token.

E.g. if you receive:

m12

Is this Message 12, or is it the first part of message 122?

If you receive:

i-12

Is this an integer -12 or is it the first part of an integer -124354?

So I think you need to change it so that the message numbers are fixed width (e.g. four digits), the string length is fixed (e.g. 6 digits) and the integer width is fixed at 10 digits.

So your example would be:

m_133s____11:Hello Worldi____-57989b0b1b0

That way if you get the first part of a message you can store it and wait for the remainder to be received before you process it.

You might also consider using control characters to separate message parts. There are ascii control codes often used for this purpose, RS, FS, GS and US. So a message could be

[RS]FieldName[US]FieldValue[RS]fieldName[US]FieldValue[GS].

You know when you have a complete message because the [GS] marks the end. You can then divide it up into fields using the [RS] as a separator, and split each into name/value using the [US].

See http://en.wikipedia.org/wiki/C0_and_C1_control_codes for a brief bit of information.

Upvotes: 1

Related Questions