Before I did the game, my main task was to implement various communication protocols based on TCP, UDP or serial port. When I want to design a TCP-based network game protocol, the feeling should be very simple, before the various international standards of the agreement has been implemented, the custom protocol is not extremely easy. But the fact that I finished my face tells me that the design protocol itself is much more difficult than it is to achieve it.
First of all, what is a communication protocol, two processes that cannot share data want to exchange data, which requires two conditions: 1. Mechanisms for sending and receiving data 2. Encapsulation and resolution of data provisions. The first condition is the physical layer, link layer, network layer, Transport Layer Network protocol family do things, the second condition is a set of application layer communication protocol. If we are using a TCP-based network to transmit data, the simple thing to do is to consider logic, because the underlying is a reliable connection based on the data flow. What is the simplest protocol? I think it's possible that the sender has only two states of information to pass, so it's enough to connect and disconnect, and nothing to send. However, if TCP is used, the connection requires three handshakes, and four handshakes are required to disconnect the connection, and the process obviously sends a large amount of data. So the simplest case of application level, should be the use of UDP communication between the two, send arbitrary messages over time and do not send any messages, both states, and does not require reliable state.
Well, the brain is finished, said the network protocol design in the swim. Where do you start? We only consider the requirements of the logic application, the transmission uses the TCP protocol, and the TCP protocol is the data flow protocol. So the first question comes, how to determine the head and tail of the data stream? This question is also subject to discussion:
Case 1. The sender and receiver maintain TCP long connection, sending rate <= receive rate. Then theoretically the sender can only specify the message length at the beginning of each complete message, and the receiver can parse each message correctly.
Scenario 2. The sender and receiver maintain TCP long connection, send rate > receive rate. At this time the receiver had to discard some data that was too late to process, but once it was discarded, he could no longer know where the header of the message was, so each message header would have a mark indicating "This is the beginning of a message."
Scenario 3. There is a TCP short connection between the sender and the receiver. This means that the frequency of sending and receiving is low, and the sender is not able to send unsolicited, only sent by the recipient after the request, such as the HTTP protocol. In this case, message processing can be considered as a single message each time it is sent, which is theoretically the simplest.
Hand tour inside the situation 3 is more common, hand travel has a feature is the mobile phone network is easy to lose, in the mobile constantly lost and rebuilt. This directly causes the TCP short connection to be unreliable, because the packet is lost in a certain ring after the network is disconnected, but we can not let the client back into the file as the end of the tour, but let the client reconnect the request. In order for both the client and the server to handle the packet loss caused by the network failure, I added the protocol serial number to the protocol layer. The rule is very simple, the client sequence number starts from 1, the server sequence number starts from 0, the server receives a message the ordinal +1, also equals the client's message sequence number, returns the message to the client, the client confirms the message serial number consistent. The client next message is ordinal +1.
This way, if the client sends a message and does not receive a response, it times out, prompting to resend the message or discard it.
If the server does not receive the lost message, the client re-sends the same as the first send effect, and the serial number grows normally.
If the server has received a message that returns a message that the client is missing, the server sequence number has increased, the message sequence that receives the client's re-send is equal to the server ordinal, and the server returns the last message cached.
If the network is abnormal, the client 1th message is sent too slow, and then the re-sent successfully, the 1th message reached the server, the server thinks the message expires, will not respond to this message.
The client wants to have a send queue, resend queue, receive queue. Each message sends this message from the send queue to the resend queue, and each response packet is sent to the resend queue to delete a message and join the receive queue.
All other cases are bugs.
Now let's look at the basic components of the network communication protocol:
[Message length] [Check code] [Protocol number] Ordinal [Message body]
It's not the end, it's just the beginning. We return to the game, when the player is playing the game is a number of players to a server, then obviously the server needs to distinguish which message belongs to which player, so in the protocol number after the layer need to add playerID.
[Message length] [Check code] [Protocol number] [playerID] Ordinal [Message body]
Well, in fact, in addition to the players, the operation of the game is also participating in the game, they need to use the GM command cheats cheat, become pseudo big R players. At this time our agreement is not enough, I can not give each operator a special playerID bar (my playerid here is dynamically generated, the player each login assigned). In addition to communicating with the player, the server communicates via protocol between internal server processes. To differentiate between the various communication purposes, we need to add a channel number to the message header of the protocol.
[Message length] [Check code] [Channel number] [Protocol number] [playerID] Ordinal [Message body]
I want to explain why the first number, but put the message head in such a position. Because each player maintains a sequence number, there is no relationship between players, the serial number is for a client object and a server object. Now our message format looks good, between C/S, S/S, GM players, request a smooth response, one-stop service has been formed. But the reality is always asking for more, considering this situation, one operation request of the client caused multiple data update on the server, when I want to add all the changed data in the response protocol. If a lot of similar operations, resulting in a complex response message, server and client code redundancy is error-prone, and some data can not even be added to the response message, the client must request another message before the line. For example, 80% of the operation may lead to completion of the task or achievement, I can not in so many messages add task and achievement synchronization data, if not completed, it becomes redundant data. There are various indications that a one-answer communication model is not capable of complex message synchronization.
But the above analysis is to overcome a lot of historical problems to get the results, always can not be overturned, and solve these problems again. Wit like me, think of a solution: Add a set of protocol number, as the server Response message sub-protocol number, sub-protocol can be freely spliced.
[Message length] [Check code] [Channel number] [Protocol number] [playerID] Ordinal [Sub-protocol number] [Sub-protocol length] [Sub-Protocol body] [Sub-protocol number] [Sub-protocol length] [Sub-protocol body] ...
In this way, the problem of the communication layer is solved by the outer layer of the Protocol head, and the logic plane problem is solved by each sub-protocol. Haha, I was so witty.
However, things are far from over, the client uses the C # language, the server uses the C + + language, the memory layout is not the same, the alignment is not the same, perhaps due to different devices and the size of the end of the problem. In order to solve the problem of realization level, also experienced twists. I don't start talking about the time relationship. Client from the beginning of the synchronization interface to the asynchronous interface, increased time-out to re-connect, solve the broken packet stitching, manual resolution changed to automatic parsing. The server from the active shutdown connection, to the client actively shut down the connection, resolved the static send cache bug, from the main thread processing message to the IOCP thread pool to process the message directly, a reply to the communication model into a one-to-many model. Finally, both the client and the server do protocol encryption. It's a piece of crap, a system of urine.
Communication protocol for logic files of hand-travel system