Unity networked game backend server framework and language

Author: Cockroach Bully
Link: https://www.zhihu.com/question/381711152/answer/3083699647
Source: Zhihu
The copyright belongs to the author. For commercial reprint, please contact the author for authorization, for non-commercial reprint, please indicate the source.
 

This article will explain the design and implementation of the Unity client network architecture from the following aspects :

1. Selection of network communication protocol

2. Design of client network framework

3. Realization of network communication

4. Code implementation

right! There is a game development exchange group here, which gathers a group of zero-based beginners who love to learn games, and there are also some technical experts who are engaged in game development. You are welcome to exchange and learn.

1. Choice of network communication protocol

The network communication protocol is the basis for realizing the communication between the client and the server. At present, there are two commonly used network communication protocols, TCP and UDP.

The TCP protocol is a connection-oriented protocol , which has the characteristics of high reliability and good stability, but its efficiency is low when transmitting large amounts of data.

The UDP protocol is a connectionless protocol with high transmission efficiency, but its reliability is not as good as TCP.

In the design of the Unity client network architecture, it is necessary to select an appropriate network communication protocol according to the actual situation. If it is a game that requires stability and reliability of network transmission, such as MOBA games, you need to choose the TCP protocol. If it is a game that requires the efficiency of network transmission, such as shooting games, you need to choose the UDP protocol.

2. Design of client network framework

In the design of the Unity client network architecture, the following aspects need to be considered:

1. Establishment and disconnection of network connection

2. Message sending and receiving

3. Encapsulation and analysis of messages

4. Message processing and callback

Network Connection Establishment and Disconnection

In the design of the client network framework, it is necessary to realize the establishment and disconnection of network connections. The establishment of a network connection needs to specify the IP address and port number of the server , and establish a TCP or UDP connection through the Socket class. The disconnection of the network connection needs to release the Socket resource and close the network connection.

Message sending and receiving

In the design of the client network framework, it is necessary to realize the sending and receiving of messages. The sending of the message needs to encapsulate the message into a byte stream and send it to the server through the Socket class; the receiving of the message needs to receive the message byte stream sent by the server through the Socket class and parse it into a message object.

Encapsulation and analysis of messages

In the design of the client network framework, it is necessary to realize the encapsulation and analysis of messages. The encapsulation of the message needs to convert the message object into a byte stream for sending to the server; the parsing of the message needs to convert the byte stream sent by the server into a message object for processing in the client.

Message processing and callback

In the design of the client network framework, it is necessary to implement message processing and callback. The message processing needs to be processed according to the message type. For example, the login message needs to be verified by the account; the callback of the message needs to return the processing result to the game logic layer after the message is processed for corresponding processing.

3. Realization of network communication

In the implementation of the Unity client network architecture, the Socket class needs to be used for network communication. The Socket class is the basic class provided by the .NET Framework for network communication and supports both TCP and UDP protocols.

When using the Socket class for network communication, the following aspects need to be considered:

1. Establishment and disconnection of network connection

2. Message sending and receiving

3. Encapsulation and analysis of messages

4. Message processing and callback

Network Connection Establishment and Disconnection

The method of using the Socket class to establish a network connection is as follows:

Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

socket.Connect(ip, port);

The method of disconnecting the network connection using the Socket class is as follows:

Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

socket.Connect(ip, port);

Message sending and receiving

The method of sending a message using the Socket class is as follows:

byte[] bytes = message.ToBytes();
socket.Send(bytes);

The method of receiving messages using the Socket class is as follows:

byte[] bytes = new byte[1024];
int length = socket.Receive(bytes);
Message message = Message.Parse(bytes, length);

Encapsulation and analysis of messages

Encapsulation of a message requires converting the message object into a byte stream for sending to the server. The parsing of the message needs to convert the byte stream sent by the server into a message object for processing in the client. Encapsulation and parsing of messages can be achieved through serialization and deserialization .

Message processing and callback

The processing of the message needs to be processed according to the message type, for example, the login message needs to be verified by the account. The callback of the message needs to return the processing result to the game logic layer after processing the message for corresponding processing.

4. Code implementation

The following is an implementation of a simple Unity client network framework, using the TCP protocol for network communication. The framework realizes the establishment and disconnection of network connections, the sending and receiving of messages, the encapsulation and analysis of messages, the processing and callback of messages, and other functions.

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;

public class Client
{
    private Socket socket;
    private byte[] buffer;

    public bool Connect(string ip, int port)
    {
        try
        {
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.Connect(ip, port);
            buffer = new byte[1024];
            socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, null);
            return true;
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            return false;
        }
    }

    public void Disconnect()
    {
        if (socket != null && socket.Connected)
        {
            socket.Shutdown(SocketShutdown.Both);
            socket.Close();
        }
    }

    public void Send(Message message)
    {
        byte[] bytes = message.ToBytes();
        socket.Send(bytes);
    }

    private void ReceiveCallback(IAsyncResult ar)
    {
        try
        {
            int length = socket.EndReceive(ar);
            if (length > 0)
            {
                Message message = Message.Parse(buffer, length);
                OnMessageReceived(message);
                socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, null);
            }
            else
            {
                Disconnect();
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            Disconnect();
        }
    }

    private void OnMessageReceived(Message message)
    {
        switch (message.Type)
        {
            case MessageType.Login:
                LoginMessage loginMessage = (LoginMessage)message;
                bool success = Login(loginMessage.Username, loginMessage.Password);
                ResponseMessage responseMessage = new ResponseMessage(success);
                Send(responseMessage);
                break;
            case MessageType.Move:
                MoveMessage moveMessage = (MoveMessage)message;
                Move(moveMessage.Direction);
                break;
        }
    }

    private bool Login(string username, string password)
    {
        // TODO: login logic
        return true;
    }

    private void Move(int direction)
    {
        // TODO: move logic
    }
}

public enum MessageType
{
    Login,
    Move
}

public abstract class Message
{
    public MessageType Type { get; protected set; }

    public abstract byte[] ToBytes();

    public static Message Parse(byte[] bytes, int length)
    {
        MessageType type = (MessageType)BitConverter.ToInt32(bytes, 0);
        switch (type)
        {
            case MessageType.Login:
                return LoginMessage.Parse(bytes, length);
            case MessageType.Move:
                return MoveMessage.Parse(bytes, length);
            default:
                throw new ArgumentException("Invalid message type");
        }
    }
}

public class LoginMessage : Message
{
    public string Username { get; private set; }
    public string Password { get; private set; }

    public LoginMessage(string username, string password)
    {
        Type = MessageType.Login;
        Username = username;
        Password = password;
    }

    public override byte[] ToBytes()
    {
        List<byte> bytes = new List<byte>();
        bytes.AddRange(BitConverter.GetBytes((int)Type));
        bytes.AddRange(BitConverter.GetBytes(Username.Length));
        bytes.AddRange(System.Text.Encoding.UTF8.GetBytes(Username));
        bytes.AddRange(BitConverter.GetBytes(Password.Length));
        bytes.AddRange(System.Text.Encoding.UTF8.GetBytes(Password));
        return bytes.ToArray();
    }

    public static LoginMessage Parse(byte[] bytes, int length)
    {
        int offset = 4;
        int usernameLength = BitConverter.ToInt32(bytes, offset);
        offset += 4;
        string username = System.Text.Encoding.UTF8.GetString(bytes, offset, usernameLength);
        offset += usernameLength;
        int passwordLength = BitConverter.ToInt32(bytes, offset);
        offset += 4;
        string password = System.Text.Encoding.UTF8.GetString(bytes, offset, passwordLength);
        return new LoginMessage(username, password);
    }
}

public class MoveMessage : Message
{
    public int Direction { get; private set; }

    public MoveMessage(int direction)
    {
        Type = MessageType.Move;
        Direction = direction;
    }

    public override byte[] ToBytes()
    {
        List<byte> bytes = new List<byte>();
        bytes.AddRange(BitConverter.GetBytes((int)Type));
        bytes.AddRange(BitConverter.GetBytes(Direction));
        return bytes.ToArray();
    }

    public static MoveMessage Parse(byte[] bytes, int length)
    {
        int offset = 4;
        int direction = BitConverter.ToInt32(bytes, offset);
        return new MoveMessage(direction);
    }
}

public class ResponseMessage : Message
{
    public bool Success { get; private set; }

    public ResponseMessage(bool success)
    {
        Type = MessageType.Response;
        Success = success;
    }

    public override byte[] ToBytes()
    {
        List<byte> bytes = new List<byte>();
        bytes.AddRange(BitConverter.GetBytes((int)Type));
        bytes.AddRange(BitConverter.GetBytes(Success));
        return bytes.ToArray();
    }

    public static ResponseMessage Parse(byte[] bytes, int length)
    {
        int offset = 4;
        bool success = BitConverter.ToBoolean(bytes, offset);
        return new ResponseMessage(success);
    }
}

The above code implements a simple Unity client network framework, using TCP protocol for network communication. In this framework, the client can establish and disconnect network connections, send and receive messages, and process and call back different types of messages accordingly.

Author: Abo's game circle
Link: https://www.zhihu.com/question/381711152/answer/2548719506
Source: Zhihu
The copyright belongs to the author. For commercial reprint, please contact the author for authorization, for non-commercial reprint, please indicate the source.
 

At present, the mainstream game server framework programming languages ​​that can do large-scale MMORPG ARPG are:

C++: network library: libevent, libuv, iocp/epoll, reliable UDP network transmission kcp;

Serialization and deserialization: protobuf;

Protocol encryption and decryption : crypto;

http parsing library: curl;

database : mysql, redis, mongodb;

Multithreading: pthread library;

Service short pathfinding and navigation : recastnavigation

Behavior decision tree : You can search for the specific library on github;

Business logic script development: Lua and other lightweight embedded scripting languages

Java:

Network library: Netty, Mina;

Serialization and deserialization: protobuf;

Protocol encryption and decryption: crypto;

http parsing library: Java has many such jar packages, you can find them by yourself;

database: mysql, redis, mongodb;

Multi-threaded Java Thread library;

Service short pathfinding and navigation: recastnavigation Java version

Behavioral Decision Tree: also available in Java;

C# and Go are not very familiar, you can find . It is recommended to write and glue the framework of the game server by yourself. The server has very good requirements on stability, so it is better to write it yourself. :

Guess you like

Origin blog.csdn.net/qq_21743659/article/details/132022206