BGE Slow Networking

Hello,
First of all I would like to apologize if I made any mistakes posting this thread, so please correct me if I made any.

Now to the problem:
I made a relativly simple Multiplayer test in BGE.
Everything seems to work fine, however the performance is quite poor, not super poor, but still I would call it unplayable. All of this was tested on LAN, so there shouldn’t be a problem with that and I also have quite a good PC which is definitly capable of rendering a few cubes.

Instructions:
Both Server and Client have Q to finish all the threads and Quit properly so please don’t use the ESC key to Quit the Game, but in case you do simply close and reopen the Server/Client.

I would like to thank you in advance for any help.

P.S.
Please don’t judge my bad coding style, because this test was made fairly quickly, so I didn’t really care for OOP :slight_smile:

Attachments

Server.blend (499 KB)Client.blend (503 KB)

A few things.

  1. Don’t ever share BGE data between threads. It’s not thread safe.
  2. Don’t use TCP for fast-paced games. The supposed benefits (Reliable ordered stream) are outweighed by their implementation costs - random unpredictable latency in stream preventing any data being received.

Latency could be anything, particularly point 2. It is fine over the local loopback network, so it’s probably socket related.

  1. Can the problem be solved using Queues?
  2. I agree, totaly forgot about UDP, so I should define socket.SOCK_DGRAM in the parameters of the socket and store the addresses to differentiate between Clients?

And how would I know when the Clien has connected, so that I can start a new thread?

Thank you for your respone.

To be honest, unless your networking logic - polling sockets, and decoding the data, takes a long time, it is just as easy to do this without threads. If you keep your network layer separate from the logic layer, then when the logic systems ask for any network messages, it is up to the network layer whether this invokes a socket.recvfrom() call, or simply returns and empties a message queue from a thread. Start simple, w/o threads if I were you.

To avoid threads, you will need to use non-blocking sockets. NB, to improve performance in blocking servers, sometimes introducing a small delay (use socket.settimeout instead of setblocking) so that you’re not polling the socket at some fraction of the clock speed.

The important thing to note is that there is a large paradigm shift between UDP and TCP. TCP abstracts the nature of the internet - maintains the illusion of a connection, and hides the notion of packets (instead representing a stream of bytes). With UDP you must recreate this support yourself. With UDP you send finite-sized packets.

TCP sends a handshake packet for connections, and either a disconnect packet or timeout for disconnection.

It is often most helpful to define a very simple system that implements packet acking (to detect dropped / incredibly late packets), and then build the notion of connections and your serialisation system separately.

For example, here is my network class, which dispatches data to the appropriate connection system

Here is the connection class, which handles packet acking

The replication layer communicates with the connection by a message passing system, and a send() method.

All of these layers are separate from one another, so that the network could implement itself in a thread, and dump packets into a queue for later dispatching.

With my design, there are several areas which assume non-threaded design, but you can make different assumptions

I see you really know your networking stuff :slight_smile:

Actually I tried using socket.setblocking(False) in the first place, but the packets weren’t transfering for some reason, there were also no errors. So I tried it with threads as I use them in my GUI applications.

I’m already working on a UDP replacement, but I will give the socket.settimeout() function a try, so that I can avoid Queues and other Threading problems.
Will keep you posted on progress.

As far as the other stuff like packet coruption detection goes, mabye I will add it down the road, but for now I will just try to make a fast and simple working example that isn’t lagging like previous.

Thanks for your help.

So I made a UDP replacement for TCP and swicthed threads for non-blocking sockets. Now it works really good with one client, however when more clients connect it starts lagging really bad and I have no idea what the problem could be.
Server.blend (501 KB)
Client.blend (506 KB)

  1. Don’t use TCP for fast-paced games.

Just because you prefer to use UDP doesn’t stop TCP from being viable. TCP works just fine.

I have heard that WOW uses TCP(correct me if I’m worng), but I think that agoose77 has a point here, since I am doing this tests for a shooter.
But since I tested both options I can tell, that using TCP wasn’t a problem, the problem were threads for some reason…
Since I switched to non-blocking sockets the performace has sky rocketed, but there were also new problems created.

Tcp is a fundamentally inadvisable choice of protocol for “fast paced input” games, such as shooters.

I prefer UDP, yes, but it is also true that TCP makes many things a breeze when writing small projects (like connection management, ordering).

However, TCP is an illusion of reliability. Just like UDP, packets are dropped occasionally / arrive late. When this happens, the stream initiates a resend, and buffers/drops later packets, and any later data to be transmitted by the sender is queued until the original resend succeeds. With Internet connection this introduces an often runaway latency, as secondary resends fail etc. UDP isn’t free from the nature of the Internet, but allows you to ‘recover’ time sensitive packets if they arrive out of order, and avoid large resends by only resending a minimum subset of dropped packets (which the application specifies) to be resent.

In short doing the reliability, ordering and flow control at the application level gives you better performance characteristics.

Although I recognise that when beginning with networking / programming, this is likely something beyond a novice, I think It is harmful to take the file object abstraction too seriously when performance (for games) will become a problem.

I’ll check it out later :slight_smile:

So, some comments:

Your issue is a combination of two separate issues.

  1. If you return after a single recvfrom call, you will only receive on packet. For a logic tick rate of 60Hz, that’s 60 packets/second. That means for 3 clients, 20 packets of their sixty will be processed (bad). To fix this, read until an OSError occurs (and check the error code to ensure it failed because no data was available), rather than returning at the first successful call.

  2. You are using a small timeout. There’s no need to use a timeout in a game engine, unless you’re using a thread. Just use setblocking(False).

Sorry, but I don’t completely understand what you mean with the: “read until an OSError occurs”.

I do understand the problem and I have switched the settimeout() to setblocking(False) and added an OSError exception.
But now I don’t know how to read until an OSError occurs, with a while loop maybe, but that would lag the program…
Would you be so kind and provide a simple corrected code example from my code?

Thank you for your help.

A while loop won’t lag the program in this case, as you will receive a small, relatively finite number of packets. When no packets are available, an oserror is raised, indicating you’re done

Sent from my SM-G920F using Tapatalk

Thank you sir, you are a genius!!
It’s now working as expected. I am going to leave this thread unsolved, for a few more days so I can test the example fully.
But once I test it and if it’s working properly I will upload the working versions and mark the thread as solved.

Thank you again :slight_smile:

Ok so I thought I was going to study, but I just had to finish this :slight_smile:

Some info if someone is going to use this
The Multiplayer example isn’t really usefull for real games, it is just a simple proof of concept.
Its problem is that you can interact with other players. If you want interaction, you should transform this into a Server based interaction system. What I mean by that is that only commands(key presses) should be sent to the Server not player position and rotation and the Server should take care of all the physics, rules and object interactions and than send out the positions and rotations to all players.

A very good video example by Goran:

Instructions(If you want to use the example):

  • Use Q to Quit on Client/Server, WASD to move around and Mouse to look around,
  • if you try connecting multiple Clients to a Server, make sure to set a unique name for each Client.

And again thank you agoose77 for helping :slight_smile:

Files:
Server_UDP.blend (502 KB)
Client_UDP.blend (508 KB)

This depends on your games architecture.

True, but I think most people will want the Server controlled version, don’t you think so?

Why?

You can implement a peer-to-peer too. It depends how you want to decide which instance of the game is right and which instance needs to be corrected. You can even do this in parts (e.g. one area is “mastered” by one instance, another by another instance) this can balance the workload on several peers rather than everything on a single instance.

Indeed it invites to cheating. But who has the server can cheat anyway.

But, you are right - one of the simplest and most common architectures is the star-design (one server multiple clients).

Even with that you need to deal with latency. A game where you see the results of your actions after half a second is nearly unplayable. In a lot of cases all instances “simulate” the same game. But they get corrections by the server, which combines all the inputs and decides the results.

Therefore you need to transfer user input (towards the server) and scene update data (towards the clients).

Ok, thanks for the explanation.
So what you’re telling me is that I shouldn’t rely 100% on the Server for transform data, but the Server should be there only for correcting the object position/rotattion…? That’s smart it would take some stress away from the Server, since I don’t have a powerful one.
Didn’t really think of this. Thanks for the Idea I will try it, because it would be quite easy to mod the current system for that.

Monster is pointing out that there are down sides in every system architecture. Server authoritative makes certain things easier (cheat prevention, authority resolution (who has “authority” over what), lobby management, …), but also has its downsides (more complicated design than simple peer to peer (but p2p becomes complicated with more advanced designs, so null point), more bandwidth use on host, host assumed safe (not cheating to his/her benefit)).

With either model, you must consider what happens when packets are dropped, when packets take some finite time to arrive, how much control players have over the game-state (could I, for example, knowing your protocol (by reading the source files, or inspecting the messages sent over the socket), send bogus messages to give myself additional features / points, or kick players? Could I pretend to be another player and do stupid things to lose them points? Etc…

Treat networking like a part of your game, rather than a bolt-on at the end. This way, you will invest the required time to address these concerns, and know when it’s okay to stop.

With either model, there is latency between the two peers, and so they will move forward in time by some value (approximately RTT [round trip time] / 2) before they receive the “latest” packet from the other peer. To put it another way, they receive the other peer’s state “late”. This happens both ways. Of course, this creates a problem, as both peers may diverge and move ahead in time, and disagree on what they did with respect to one another. This is the main aspect of networking that you will have to deal with.