jmasterx
jmasterx

Reputation: 54113

Good way to start communicating with a client?

The way my game and server work is like this:

I send messages that are encoded in a format I created. It starts with 'p' followed by an integer for the message length then the message.

ex: p3m15 The message is 3 bytes long. And it corresponds to message 15. The message is then parsed and so forth.

It is designed for TCP potentially only sending only 1 byte (since TCP only has to send a minimum of 8 bits).

This message protocol I created is extremely lightweight and works great which is why I use it over something like JSON or other ones.

My main concern is, how should the client and the server start talking?

The server expects clients to send messages in my format. The game will always do this.

The problem I ran into was when I tested my server on port 1720. There was BitTorrent traffic and my server was picking it up. This was causing all kinds of random 'clients' to connect to my server and sending random garbage.

To 'solve' this, I made it so that the first thing a client must send me is the string "Hello Server".

If the first byte ever sent is != 'H' or if they have sent me > 12 bytes and it's != "Hello Server" then I immediately disconnect them.

This is working great. I'm just wondering if I'm doing something a bit naive or if there are more standard ways to deal with:

-Clients starting communication with server -Clients passing Hello Server check, but somewhere along the line I get an invalid message. I can assume that my app will never send an invalid message. If it did, it would be a bug. Right now if I detect an invalid message then I disconnect the client.

I noticed BitTorrent was sending '!!BitTorrent Protocol' before each message. Should I do something like that?

Any advice on this and making it safer and more secure would be very helpful. Thanks

Upvotes: 2

Views: 150

Answers (2)

Jonathon Reinhart
Jonathon Reinhart

Reputation: 137398

Typically, I design protocols with a header something like this:

typedef struct {
    uint32_t    signature;
    uint32_t    length;
    uint32_t    message_num;
} header_t;

typedef struct {
    uint32_t    foo;
} message13_t;

Sending a message:

message13_t msg;
msg.foo = 0xDEADBEEF;

header_t hdr;
hdr.signature = 0x4F4C494D;         // "MILO"
hdr.length = sizeof(message13_t);
hdr.message_num = 13;

// Send the header
send(s, &hdr, sizeof(hdr), 0);

// Send the message data
send(s, &msg, sizeof(msg), 0);

Receiving a message:

header_t hdr;
char* buf;

// Read the header - all messages always have this
recv(s, &hdr, sizeof(hdr), 0);

// allocate a buffer for the rest of the message
buf = malloc(hdr.length);

// Read the rest of the message
recv(s, buf, hdr.length, 0);

This code is obviously devoid of error-checking or making sure all data has been sent/received.

Upvotes: 0

user1252446
user1252446

Reputation:

perhaps a magic number field embedded in your message.

struct Message
{
    ...
    unsigned magic_number = 0xbadbeef3;
    ...
};

so first thing you do after receive something, is checking whether the magic_number field is 0xbadbeef3.

Upvotes: 2

Related Questions