Small and medium-sized mobile phone chess and card network game server architecture design (with source code)

The implemented logic is different from the previous description: h5.h5.hxforum.com Contact information 170618633533 Penguin 2952777280 Source code sale Room card sale Backstage
rental DBProxy changed its name to DB 
2. Proxy holds multiple connections to different types of servers (Login, Game) at the same time 
3. DB does not participate in load balancing, considering that the load of the chess and card database is not high, even if it needs to expand multiple servers, it can be configured through different servers Point to different DBs to expand 
4. The message header format is mainly implemented by source code 
5. Heartbeat mechanism Without considering the client, the server will actively send heartbeat packets, but not always at specific intervals

If it feels obscure to read, you might as well look directly at the source code

Network

Contains three components: Server, Client, and RPC.

Server

The network server component holds the listening socket and manages all client connections (map storage, value can store custom values), a client connection starts a Goroutines to receive messages, calling Stop will wait for all Goroutines to exit before returning, Only notify the business logic of "message received" and "connection closed" two events.

Client

The network client component holds the connection with the server, implements the compensation strategy reconnection mechanism, and only notifies the business logic of two events: "client connection succeeded" and "client received message".

RPC

Remote procedure calls only implement synchronous calls. One call occupies one connection at the same time to implement connection pooling, and there is no limit to the maximum number of connections for the time being. 
Note: When the server restarts, one call will close all established connections and create a new connection to complete the call. If the server restart takes too long, the call will return an error because the connection to the server fails.

Error

It is necessary to describe the general error mechanism in detail. The error type is cross-server and cross-network. It can directly return the error or MyError type to notify the communication caller of the error. The error will be returned level by level. Golang's built-in error type will eventually create the corresponding MyError Define the error type to return, and the RPC receiver will check if it is an error message when receiving the message, and create a MyError return to indicate that the call failed.

Server

Proxy (proxy), Manager (management), Login (login), Game (game), DB (database proxy).

Proxy

Holds the Server component: accepts client connections, manages client connections, and notifies business logic when events arrive. 
Hold the Client component: connect to the Manager server, and notify the business logic when the event arrives. 
When the connection to the Manager is successful, a registration service message (number, listening address, service type) will be sent. 
When the client message arrives, check whether there is a session bound to the conn, if not, create a binding, and finally the message is always handed over to the session for processing. 
The client connection is closed, check whether there is a session bound to the conn, and close the session if there is. 
Receive the Manager notification service message and update the locally available service information reasonably.

Session

The session currently holds three connections: client (client), login (login), and game (game). The most basic purpose of existence is message forwarding. 
There are three connection states for the session, safe state (indicating that the client has been sending messages to the server, and the average interval does not exceed ten seconds), warning state (the client has not sent a message to the server for at least the last ten seconds), and the death state ( The client has not sent a message to the server for at least the last 20 seconds, and does not even reply to the heartbeat packet sent by the server ten seconds ago.) When the session receives a message from the client, it always sets the session state to a safe state. 
At present, only this layer implements heartbeat detection and keep-alive (there is no heartbeat between the server and the server), and a session starts a Goroutines intermittent cycle to keep alive (original I also wanted to keep alive all sessions uniformly, the biggest advantage is that only use A Goroutines, but this must maintain the session set, because it involves adding and deleting sessions, and it must be locked again. I don’t want this, so I adopted the current scheme), check the session status every ten seconds, and always decrease the status value to the death state , when the session state is a warning state, try to send a heartbeat packet to the client, and when the session state is a dead state, close the session. 
Always close the original connection established with the login when receiving the client's quick registration message, re-create the connection, start a Goroutines to receive the login server message, and do not connect to the login server when the client connection is established. A layer of protection prevents attackers from maliciously establishing connections and penetrating to the login server. Here, the client message will be re-serialized and the client address will be filled. After all, only the real address of the client is known here, and other types of messages sent to the login server are not. It is allowed to precede the quick registration message, otherwise the session will be closed directly. When receiving the quick registration message from the login server, the message will be parsed, and the user ID will be taken out and recorded in the session, so that the user ID can be filled when logging in to the game server quickly. 
Always close the original connection with the game when receiving the client's quick login message, re-create the connection, and start a Goroutines to receive the message from the game server. The client's quick login message only needs to provide "game type (Doudizhu)" "Game Level (Novice)", where the correct connection is established by finding the corresponding service, the message will be re-serialized here, and the "User ID", "Timestamp" and "Signature" will be added. The timestamp and signature are just to ensure that the game server receives The quick login message that arrives must be sent by my agent server (for details, please refer to the source code, and the idea can refer to the WeChat public platform access verification). Other types of messages sent to the game server are not allowed to precede the quick login message, otherwise it will be closed directly. session. 
When the user disconnects from the agent, it will trigger to close the session, notify the keep-alive Goroutines to exit, close the connection with the login game, the two receiving message Goroutines will exit, and the connection with the client will be released next, no more Who binds the session, so the session will be GC (garbage collection). 
Regardless of the failure to receive login or game messages, the receiving Goroutines will exit, will close the connection with the client, and then close the session. 
After receiving the user logout message, the session directly closes the connection with the game server.

Manager

Holds the Server component: accepts client (Proxy, Login, Game) connections, manages client connections, and notifies business logic when events arrive. 
Two service sets are maintained, one is all services (all enabled services), and the other is selected services (services selected after the load balancing policy). 
Receive the registration service message, record the corresponding network connection, and record the service in all service tables. If there is no similar service in the selected service table, the selected service table will record the service at the same time. If the registration service type is proxy, it will notify the current The optional service is used to initialize the locally available services of the agent. 
When the connection is closed, the service will be searched through the connection, and the service will be deleted from all service tables. If the service exists in the selected service table, it will be deleted. It will try to obtain similar services from all service tables, and if it is obtained, it will be added to the selected service table. 
After receiving the update count message, update the count value of the corresponding service. The following logic will be triggered only when the count value is higher than the capacity threshold. If the service exists in the selected service table, delete it, and try to obtain similar services from all service tables. If it is obtained, it will be added to the selected service table, but if the same service is to be deleted and added, the preceding delete and add service logic will not be triggered. 
After receiving the service start message, set the corresponding service start flag. If there is no similar service in the selected service table, the selected service table records the service. 
After receiving the shutdown service message, set the corresponding service shutdown flag. If the service exists in the selected service table, delete it, try to obtain similar services from all service tables, and add it to the selected service table if it is obtained. 
There are three previous uses to obtain similar services. In fact, load balancing is implemented here. Each call will always return the Proxy and Login services with the smallest count value, and the Game service with the largest count value but not exceeding the capacity threshold (if both exceed the threshold, return The smallest), let users play in the same game service as much as possible, and it is convenient to quickly set up tables to start the game. 
As mentioned earlier, whether it is adding or deleting a selected service, all registered agents will be notified.

Login

Holds the Server component: accepts the connection established by the Proxy simulates the client, manages the connection established with the Proxy, and notifies the business logic when the event arrives. 
Hold the Client component: connect to the Manager server, and notify the business logic when the event arrives. 
Hold RPC component: connect DB database proxy. 
When the connection to the Manager is successful, a registration service message (number, listening address, service type) will be sent. 
After receiving the quick registration message, RPC calls the database proxy synchronously, whether it is querying an existing user or creating a new user, after the database proxy returns, it directly replies to the client, which is actually a reply to the proxy.

Game

Holds the Server component: accepts the connection established by the Proxy simulates the client, manages the connection established with the Proxy, and notifies the business logic when the event arrives. 
Hold the Client component: connect to the Manager server, and notify the business logic when the event arrives. 
Hold RPC component: connect DB database proxy. 
When the connection to the Manager is successful, a registration service message (number, listening address, game type, game level, service type) will be sent. 
After receiving the quick login message, verify the signature to ensure that it is sent by the proxy. The RPC synchronously calls the database proxy to query the user information. After the database proxy returns, it directly replies to the client, which is actually a reply to the proxy.

DB

Holds the Server component: accepts client (Login, Game) connections, manages client connections, and notifies business logic when events arrive. 
The return value of OnMessage is extended here. It supports returning nil to indicate success, returning built-in error type to indicate error, returning custom MyError type to indicate success or error, and returning other data structures to indicate the content of the reply to the client. 
Connect to MySQL database, connect to Redis cache

Note: The timer module has been implemented, and the timing time is accurate to seconds. The main logic is just encapsulation and management of the standard library Timer and Ticker. The timer is added through the global unique number, and the loop timer is supported, and the remaining time to expiration is supported.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325119814&siteId=291194637