0

I created a send-receive datagram system for a game I have created in java (and LWJGL).

However, these datagrams often got dropped. That was because the server was waiting for various IO operations and other processing to be finished in the main loop, while new datagrams were being sent to it (which it was obviously not listening for).

To combat this, I have kept my main thread with the while true loop that catches datagrams, but instead of doing the processing in the main thread, I branch out into different threads.

Like this:

ArrayList<RecieveThread> threads = new ArrayList<RecieveThread>(); public void run(){ while (true){ //System.out.println("Waiting!"); byte[] data = new byte[1024]; DatagramPacket packet = new DatagramPacket(data, data.length); try { socket.receive(packet); } catch (IOException e) { e.printStackTrace(); } //System.out.println("Recieved!"); String str = new String(packet.getData()); str = str.trim(); if (threads.size() < 50){ RecieveThread thr = new RecieveThread(); thr.packet = packet; thr.str = str; threads.add(thr); thr.start(); }else{ boolean taskProcessed = false; for (RecieveThread thr : threads){ if (!thr.nextTask){ thr.packet = packet; thr.str = str; thr.nextTask = true; taskProcessed = true; break; } } if (!taskProcessed){ System.out.println("[Warning] All threads full! Defaulting to main thread!"); process(str, packet); } } } } 

That is creating a new thread for every incoming datagram until it hits 50 packets, at which point it chooses to process in one of the existing threads that is waiting for a next task - And if all threads are processing, it defaults to the main thread.

So my question is this: How many threads is a good amount? I don't want to overload anybody's system (The same code will also be run on players' clients), but I also don't want to increase system packet loss.

Also, is different threads even a good idea? Does anybody have a better way of doing this?

Edit: Here is my RecieveThread class (class is 777 lines long):

 String str; DatagramPacket packet; boolean nextTask = true; public void run(){ while (true){ ////System.out.println("CLIENT: " + str); //BeforeGame while (!nextTask){ //Nothing } <Insert processing code here that you neither know about, nor care to know about, nor is relevant to the issue. Still, I pastebinned it below> } } 

Full receiving code

9
  • 1
    There generally isn't a magic number of threads that is the best. Every system varies, each processor has a different number of cores, etc. I suggest you do some exploratory analysis on performance while varying the thread count. Commented Oct 26, 2014 at 22:28
  • 1
    How long does it really take to process one datagram? I suggest you only need one thread for that, but it shouldn't do anything else, unless datagrams take an amazingly long time to process, in which case you should look into java.util.concurrent.Executor and friends. Commented Oct 26, 2014 at 22:41
  • @EJP I have got over 500 lines of processing code after receiving the packet - Many of them include IO operations as well, and some of them include intensive iterations over ConcurrentHashMaps. Commented Oct 26, 2014 at 22:43
  • @Afforess I Didn't know you were on this site - Hi! Anyway, more threads appear to use up more processing, even when idle. Is that usual? Is there any information I can get from the computer code-wise to calculate (code-wise) how many threads there should be? Commented Oct 26, 2014 at 22:46
  • @Joehot200 If you are iterating intensely over hash maps you are already doing something seriously wrong. I suggest you would do better to speed up your processing rather than build threading systems around it. Commented Oct 26, 2014 at 22:48

3 Answers 3

1

First and foremost, any system that uses datagrams (e.g. UDP) for communication has to be able to cope with dropped requests. They will happen. The best you can do is reduce the typical drop rate to something that is acceptable. But you also need to recognize that if your application can't cope with lost datagrams, then it should not be using datagrams. Use regular sockets instead.

Now to the question of how many threads to use. The answer is "it depends".

  • On the one hand, if you don't have enough threads, there could be unused hardware capacity (cores) that could be used at peak times ... but isn't.

  • If you have too many threads running (or runnable) at a time, they will be competing for resources at various levels:

    • competition for CPU
    • competition for memory bandwidth
    • contention on locks and shared memory.

    All of these things (and associated 2nd order effects) can reduce throughput ... relative to the optimal ... if you have too many threads.

  • If your request processing involves talking to databases or servers on other machines, then you need enough threads to allow something else to happen while waiting for responses.

As a rule of thumb, if your requests are independent (minimal contention on shared data) and exclusively in-memory (no databases or external service requests) then one worker thread per core is a good place to start. But you need to be prepared to tune (and maybe re-tune) this.

Finally, there is the problem of dealing with overload. On the one hand, if the overload situation is transient, then queuing is a reasonable strategy ... provided that the queue doesn't get too deep. On the other hand, if you anticipate overload to be common, then the best strategy is to drop requests early.

However, there is a secondary problem. A dropped request will probably entail the client noticing that it hasn't gotten a reply in a given time, and resending then resending request. And that can lead to worse problems; i.e. the client resending a request before the server has actually dropped it ... which can lead to the same request being processed multiple times, and a catastrophic drop in effective throughput.

Note that the same thing can happen if you have too many threads and they get bogged down due to resource contention.

Sign up to request clarification or add additional context in comments.

6 Comments

Thank you - Great answer! Out of interest, if I spam 20 packets to the client of the same data instead of 1 packet, is it more likely the client would receive the data? Obviously I would only do this for money reward packets or "xxx won the game" packets, rather than move packets.
Maybe. It depends on what strategy other clients adopted. I can imagine that everyone did this, it could get really bad; e.g. load spikes, and other problems caused by dropped packets and retransmissions. If you need reliability you should use streams.
Humour me and tell me what "Streams" are in terms of connections and stopping packet loss. Thanks.
@Joehot200 - reliable stream oriented network protocols; e.g. TCP/IP.
That is correct. Nothing is totally immune to certain kinds of network failure. Even undetectable network errors are possible with a plain TCP/IP stream. (That's why we use SSH/SST/TLS, crypto hashes and other messures when you need to be absolutely sure.) But these problems are many orders of magnitude less likely than dropping of UDP messages.
|
1

Probably just one thread, assuming you have one DatagramSocket. You could always spawn a processData thread from your thread that reads the UDPSocket. Like people said in the comments it's up to you, but usually one is good.

Edit:

Also look into mutexes if you do this.

2 Comments

Unfortunately I am getting packet loss with one thread, so I need more.
Okay, yeah make a separate class that holds your processing. Then the thread that reads the UDP data will just spawn the processing class with the data.
0

Seems you're in the same question about the doubt of using NginX or Apache. Have you ever read about the NginX and the 10k problem? If not read about here. There is no "correct" answer for questions like this one. As the other mates have highlighted this question is about the needs (aspects) of your application's environment. Remember that we have so many framework for web: every framework solve the same problem what is serving html documents but using different ways to do the task.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.