Client server message interpretation

2019-07-20 19:37发布

问题:

I'm trying to communicate data between a server and a client computer using my program. I have very little knowledge of TCP and how it works so I really need some help.

So far a message of my own simplistic protocol is defined as follows:

int _header_signature;
int _offset_a;
int _offset_b;
int _size_a;
int _size_b;
wchar_t stuff[_size_a];
wchar_t stuff2[_size_b];
int _footer_signature;

This gets serialized onto a buffer and gets send using Winsock's send() method.

My goal is to somehow interpret this message and extract the data in a similar struct on the server machine. This is a one-to-one connection between a client and a server.

How would I approach interpreting this data on the server part?

Would I:

a) Loop calling recv() writing what I receive into a buffer, and start working on interpreting the message only when recv() has nothing more to return and all of the message sent is now on the buffer? I'm also not sure what would happen if the client keeps sending messages. Will the second message let's say arrive only when the first one has finished being recv()'d? Or will recv() continue returning stuff as long as the client keeps sending messages?

OR

b) Start working on interpreting this messages as soon as they come even if only a part of a message has arrived? The header should tell how many more I should expect. (this seems a really long and tedious task to achieve)

Isn't there a way to get like the whole message received into a buffer, and somehow cast it into a struct so that I can work with the data?

I'm sorry if I confused anyone, if something is unclear please tell me and I will update the question

回答1:

You have quite a few questions bundled in one.

I think the most important one to answer for you is that when you call receive on a TCP socket, it will not magically handle receiving a whole message for you. In fact if you think about it, the only thing that is guaranteed is that you will receive data on an 8 bit-boundary. A call to receive will block until there is at least one byte available (possibly more) and it might return an empty buffer if the socket is closed.

Armed with that knowledge, you should be on your way to answering question number 2: "do you wait until a whole message is received or keep calling receive" and the answer is that you should call receive back-to-back. And parse the input buffers, as they come to deserialize the individual bytes into the data strucutre that your application protocol dictates.

One important thing to realize is that having a very large read buffer does not guarantee that you will get the whole message in a single call! This is really important to understand. It means that your code must operate under the assumption that your could be receiving as little as 1 byte at a time, and as much data as the size of your read buffer. So, when you decide on the size of the read buffer, you should pick a sensible value, based on the MTU of the network (something like 1500 bytes is typically a good choice). Every call to recv() will tell you exactly how many bytes were actually read.

Once you start receiving data, copy the data into a temporary buffer, and when you have enough to parse the header of one message, decode that and determine if you've received the whole message, or there is more pending. when you've received the whole message, pass it further to your application. All this should operate somewhat independent of the application (the receiving code should be able to accept data as fast as possible, buffer it, parse it and then feed the decoded messages to the application).