By Luo Peiyu

When developing Unity network modules, there are generally asynchronous (multithreading the same), multiplexing two methods. What are they, and which is better?

In the network module of “Unity3D Network Game Actual Combat (2nd edition)”, asynchronous client is used and multiplexing is used on the server. A reader asked why, why not use multiplexing on the client side? This is a problem that many people encounter and decided to write an article about it.

Let’s take a quick look at what asynchrony and multiplexing look like.

asynchronous

The asynchronous program is written as follows, will call the.NET network programming API, using BeginXXX and EndXXX syntax. In fact, another thread is opened inside the program to receive data.

public class Echo : MonoBehaviour { Socket socket; Byte [] readBuff = new byte[1024]; public Start() { //Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); / / Connect the socket Connect (" 127.0.0.1 ", 8888); //BeginReceive socket.BeginReceive( readBuff, 0, 1024, 0, ReceiveCallback, socket); } //Receive callback public void ReceiveCallback(IAsyncResult ar){Socket Socket = (Socket) ar.AsyncState; int count = socket.EndReceive(ar); string s = System.Text.Encoding.Default.GetString(readBuff, 0, count); socket.BeginReceive( readBuff, 0, 1024, 0,ReceiveCallback, socket); }}Copy the code

As shown below, by calling BeginReceive, the program starts a new thread that blocks and waits. Wait for a message to come back, then proceed.

multiplexing

Asynchronous programs are cumbersome to write and require a lot of code. In fact, there is a simpler way to handle asynchronous programs, which is to use poll or SELECT. The code for using poll is as follows.

Using public class Echo: MonoBehaviour {// Define Socket Socket; public void Start() { //Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); / / Connect the socket Connect (" 127.0.0.1 ", 8888); } public void Update(){ if(socket.Poll(0, SelectMode.SelectRead)){ byte[] readBuff = new byte[1024]; int count = socket.Receive(readBuff); string recvStr = System.Text.Encoding.Default.GetString(readBuff, 0, count); }}}Copy the code

In any case, this code is less than asynchronous. It works by using socket.poll, but returns true if the socket has readable data and false if it does not. So the program as long as the Update constantly check the socket state, when there is data to read, can also implement the function.

Why do clients use asynchrony

Most game programs I’ve seen use asynchrony or multithreading to handle network modules. This begs the question, multiplexing is easier to write with less code, but why not use it? It doesn’t really make much difference which way you use it in small projects, but when considering network performance, you have to be careful. Clients don’t use multiplexing for two reasons.

1. Iterate

As can be seen from the above program, in poll mode, the program must constantly check the Update, which may be 30 to 60 times per second, increasing the amount of calculation. Asynchrony does not have this problem. When the network message arrives, the thread is aroused and does not need to traverse.

2. Impact on the main thread

When receive the network data, the example used in the Encoding. The Default. Get string to a byte stream into a string, in the actual game, may use the protobuf or json protocol, the byte stream object parsed into agreements with a certain amount of calculation. In the figure below, an asynchronous program can decode in an asynchronous thread so that the program does not choke the main thread because of the decoding. The Poll program does not do this and decodes in the main thread. Unity’s scripting logic (Awake, Start, Update, Collision, CPU render) all depends on the main thread, and the less network modules affect the main thread, the better performance.

Why does the server use multiplexing

The client and the server face different situations. The client usually needs to maintain only one connection, while the service needs to maintain all connections. The core of why multiplexing is called “multiplexing” is to solve the problem of “multiple connections”.

Because the server handles the logic of each player, there may be interactions between players, such as in the picture below, where player 1 and Player 2 are in the same room.

If multithreading (asynchronous) is used, then the operation of player 1 and player 2 May have thread conflict, and the room object needs to be locked when processing logic, which is used in Unity3D Online Game Actual Combat (1st edition). If multithreading is avoided, the locking problem is eliminated, the logic is clearer, and bugs are less likely. Multi-thread processing is not a simple thing, it needs a lot of experience to deal with well, “Unity3D Online Game Combat (2nd edition)” using multiplexing to avoid this problem.

Finally, I still put an advertisement. The author’s recently published “Unity3D Online Game Combat (the second edition)” introduces the whole process of the development of online games in detail. Compared with the first edition, it pays more attention to the knowledge of network programming. After reading this book, I can make a certain scale of online games from scratch.