📜 ⬆️ ⬇️

Network programming for game developers. Part 1: UDP vs. Tcp

From the translator: This is the translation of the first article in the series “Networking for game programmers” . I really like the whole series of articles, plus I always wanted to try myself as a translator. Perhaps an experienced developers article seems too obvious, but, as it seems to me, the benefits of it in any case will be.


Hi, my name is Glenn Fiedler and I greet you in the first article from my online book, Network Programming for Game Developers.

image

In this article, we will start with the most basic aspects of network programming — receiving and transmitting data over a network. Receiving and transmitting data is the main and simplest part of the whole range of tasks that network programmers are involved in, but it is often difficult to determine which way is best to go. Pay enough attention to this part - if you have a misunderstanding, this can lead to terrible consequences for your multiplayer game in the future!

You, most likely, already heard something about sockets, and, probably, know that they are divided into two main types - TCP and UDP. The first thing to decide when developing a multiplayer game is which type of sockets to use - TCP, UDP, or both?

The choice of the type of sockets depends entirely on the genre of the game you are developing. In this series of articles, I will assume that you are writing a game in action style — like Halo, Battlefield 1942, Quake, Unreal, CounterStrike, Team Fortress, etc.
')
Now we will take a closer look at the properties of each type of socket (taking into account the fact that we are developing the game in the style of action), and delve into the details of the work of the Internet. After a detailed review, the correct version will become obvious!

TCP stands for “transmission control protocol”, and IP as “internet protocol”. Together, they are the basis of virtually everything that you do on the network, from browsing the web and ending with IRC communication and e-mail — it all works on a TCP / IP basis.

If you have ever used TCP sockets, then you should know that TCP is a protocol that uses the principle of a reliable connection. This means that you establish a connection between two computers, and then transfer data between them just as if you were writing information to a file on the same computer, and on the other - would read it from the same file.

In this connection is considered reliable and consistent - that is, all the information that you send, is guaranteed to reach the recipient in the same order in which it was sent. Also, a TCP connection can be considered a continuous stream of data - the protocol itself takes care of breaking the data into packets and sending them over the network.

Once more - everything is simple, as usual writing or reading from a file. Elementary Watson!

But such ease of handling is completely different from what is actually happening “under the hood”, at a lower level - the IP protocol level.

At this level, there is no concept of connection - instead, individual packets are transferred from one computer to another. You can imagine this process as the transfer of a note from one person to another in a room full of people: in the end, the note goes to who you need, but at the same time having gone through many hands.

However, there is no guarantee that the note will reach the addressee. The sender simply sends the note in the hope that it will come, but at the same time does not even know whether the message has reached or not - until the recipient decides to write in response.
Naturally, in reality, everything is a bit more complicated, since the sending computer does not know the exact sequence of computers on the network through which the packet must be transmitted in order for it to get as quickly as possible. Sometimes IP transmits multiple copies of the same packet, which can go to the addressee in different ways - and, most likely, reach at different times.

This is because the Internet is a self-organizing and self-healing system that can “bypass” problem areas in the network. In fact, what happens at such a low level in the network is really cool. You can read about this in more detail in the already classic book - “TCP / IP Illustrated” .

But what if we want to send information between computers not in the style of reading / writing to a file, but directly sending and receiving individual packets?

Well, we can do this using UDP. UDP stands for “user datagram protocol”, and it works over IP (just like TCP), but instead of adding heaps of functionality, it is just a small add-on over IP.

Using UDP, we can send a packet to a specific IP address (for example, 112.140.20.10) and a port (for example, 52423), and it will be transferred from computer to computer until it reaches the goal (or is not lost along the way).

At the same time, on the receiver side, we simply sit and wait, listening to a specific port (52423 in our case), and when a packet comes from someone (remember that connections are not used), we receive a notification about this with the address and port of the sending computer, packet size, and after that we can read data from this packet.

UDP does not guarantee data delivery. In practice, most of the packages, of course, reach, but there are always losses of around 1-5%, and sometimes there are periods of time during which the packages do not reach at all (remember that there can be thousands of computers between any sender and receiver). it may fail or break).

Also, UDP does not guarantee the order of delivery of packets. You can send five packets in order - 1, 2, 3, 4, 5 - and they can come in a completely different order - for example, 3, 1, 2, 5, 4. Again, in practice, they will most likely come in the correct order in most cases, but you cannot rely on it!

Finally, even though UDP doesn’t add anything to IP, one thing it does guarantee. If you send a package, it will either reach completely or not reach at all. So, if you send a packet of 256 bytes to another computer, then it cannot receive only the first 100 bytes of the packet — it must receive all 256 bytes. This is really the only thing that the UDP protocol guarantees - everything else falls on your shoulders.

So, we need to decide - to use TCP or UDP sockets? Let's take a look at their properties:

TCP:

UDP:

With this list, the solution seems obvious - TCP implements all the functionality we need and is easier to use, whereas using UDP promises hemorrhoids with writing everything in the world manually, from scratch. So we use TCP, right?

And no.

Using TCP is probably the worst mistake you can make when developing a multiplayer game. To understand why, let's see what makes TCP so easy to use!

How TCP works

TCP and UDP both work on top of IP, but in fact they are completely different. UDP behaves very similar to IP, while TCP abstracts the user from all problems with packets, making interaction with it look like reading / writing to a file.

So how does he do it?

First, TCP uses a data flow abstraction — you can simply write data bytes to this stream, and TCP will ensure that they reach the destination. Since IP transmits data in packets, and TCP runs on top of IP, TCP must break the user's input stream into separate packets. Thus, inside TCP, some logic collects data into a queue, and when it accumulates quite a lot, it forms a packet and sends it to the addressee.

This behavior can be a problem for our multiplayer game if you need to transfer very small packets. It may happen that TCP decides not to transmit our data until it has accumulated enough to form a packet of a certain size (say, more than one hundred bytes). And this is a big problem, because it is necessary to transfer data from the client (keystrokes of the player) to the server as quickly as possible, and if at the same time there will be delays due to buffering the data with the protocol, then the player on the client side will not play the game in a pleasant way. At the same time, the game objects will be updated with a delay and rarely - whereas we need to make objects update on time and often.

In TCP, there is an option to fix this - “TCP_NODELAY”. She speaks to the protocol so that he does not wait for the accumulation of data in the sending queue, but sends them immediately.

Unfortunately, even with this option installed, TCP has a lot of problems when using it in online games.

The root of all the problems lies in how TCP handles packets that are lost or out of turn, creating the illusion of a reliable and consistent connection.

How TCP provides reliable connection

When transmitting, TCP splits the data stream into separate packets, forwards them over the network using unreliable IP protocol, and then restores the original stream from the received packets to the receiving computer.

But what if one of the packages does not reach? Or if packages come out of order, or with duplicates?

If you don’t go deep into the details of TCP operation (and this is a really difficult topic - you can read in TCP / IP Illustrated), the process looks like this: TCP sends a packet, determines that the packet has not reached, and resends the same packet to the addressee. Duplicate packets are eliminated on the side of the addressee, and packets that do not arrive in order are reordered so that everything is as it should be — reliable and in order.

The problem is that when TCP “synchronizes” the data stream in this way, in case of packet loss, transmission stops until the lost packet is sent again (and received by the addressee). If, while waiting, new data arrives, they will be queued, and you will not be able to read them until the same lost packet arrives. How long does it take to send the package again? It takes at least the time equal to the time it takes for the packet to go back and forth (when TCP determines which packet to send again), plus the time it takes to retry the lost packet. So, if the ping between computers is 125 ms, the retransmission of the packet will take about one fifth of a second, and in the worst case, up to half a second (imagine if the newly sent packet is also lost). Have fun!

Why you should never use TCP for multiplayer games

The problem with using TCP in online games is that, unlike browsers, email and other applications, games are tied to real-time interaction. For many aspects of the game, for example, the keys pressed by the user and the position of the players in the game, it does not matter what happened a second ago, and only the most current state of the game world is important.

Consider a simple example of a multiplayer game, for example, a 3d shooter. The network part in the game is very simple: every iteration of the game cycle the client sends to the server a description of all player actions (keystrokes, mouse position, etc.), and every iteration the server processes this data, updates the model of the game world and sends the current the positions of the objects of the world so that the player will draw a new frame.

So, in our game, if a packet is lost during transmission over the network, the game stops and waits until the packet is delivered again. On the client side, game objects freeze, and on the server, players also cannot move or shoot, as the server cannot accept new packages. When the lost packet finally arrives, it contains already outdated information, which is already irrelevant. In addition, after that all those packets that have accumulated in the queue during the waiting time come, and they all need to be processed in one iteration of the loop. Complete confusion!

Unfortunately, it is impossible to change such TCP behavior, and it is not necessary, since the meaning of TCP lies in it. It is a necessity to make data transmission over the Internet a reliable and consistent stream of data.
But we do not need a reliable and consistent data flow.

We need to get the data from client to server as quickly as possible, and we don’t want to wait for the data to be sent again.
This is why you should never use TCP for multiplayer games.

But wait! Why can't I use both UDP and TCP together?

For real-time game data, for example, user clicks and the state of the game world, only the most relevant data is important, but for other types of data, such as instruction sets sent from one computer to another, reliability and channel consistency can be very important.

Of course, the temptation is great to use UDP to transfer user input data and the state of the world, and TCP for those data that must be guaranteed to be delivered. You may even think that you can make several “streams” of commands — for example, one for loading levels, another for AI commands. You think: “I don’t need the AI ​​teams to wait in the queue if the data package is lost for loading the level, because they are completely unrelated!”. In this case, you are right, and you can decide to create a TCP socket for each stream of commands.

At first glance, this is a great idea. But the problem is that since TCP and UDP both work on top of IP, the packets of both protocols will affect each other — already at the IP level. How exactly this influence will manifest itself is a very complex issue, and it is connected with the mechanisms for ensuring reliability in TCP. But, in any case, be aware that the use of TCP usually leads to an increase in UDP packet loss. If you want to know more about it, you can read this article.

Conclusion

I recommend not only using UDP, but using only UDP and nothing else. Do not use TCP and UDP together - instead, learn better how to implement those TCP chips you need on your own, based on UDP.

In the next articles, I will tell you how to do this - from implementing your own protocol using UDP-based connections to implementing ensuring the reliability of transmission and control of data flow.

Source: https://habr.com/ru/post/209144/


All Articles