0

Some Background Information: For a school project, we need to program a little network game which allows at least two players on different pcs to play together. So we decided to code a simple looking 2D Bomberman. The problem was that we never had any experience with multiple threading and didn´t know how to make a real thread safe application. So far we made a javafx gui and gave the character some possibilities like placing 3 bombs or run around the gamefield of auto generated blocks which can force the player to stop because of collision detection. All that came with no real big problems. But then begun the tricky part. How could we realise a working multiplayer part without any knowledge of Sockets and Threads? Since two weeks I´ve startet to learn the simplest and required parts of this two topics, but I couldn´t find a good solution for our problems, even on Stackoverflow. There are some topics, but there is nothing that special like sending player positions in real time over an tcp socket using the Java.net.Socket class. Am I right?

So tried something out and made 2 essential classes for the whole communication, based on different Threads. One named NetworkSupport (working with Sockets), which is responsible for the let´s say lower Network stuff, like creating a working connection between the clients and the host and another one named NetworkBridge which has the task to evaluate incoming messages and react with a specified method, for example to move the player to point(x,y) on the scene. So where is the problem.

Network Support uses BufferedReader und BufferedWriter on the streams of different client Sockets saved in an ArrayList. The "recievedData" comes in a so named StringBuilder and is read from the NetworkBridge class launched by another Thread. The messages like the positions come through, but they come very, very slowly and I don´t know why. I made different tests with timestamps to find out the bottle neck, but I failed.

So is this a problem of my frehsly learned synchronisation skills or is it the BufferedReader or anything else I made wrong?

What would be the best solution to share movement position between programs?

And the most important question: What can I do to solve these slow sending speed without the constraint to make big changes?

Thanks for any replies.

Here´s a Sample of the NetworkSupport´s class recieve Method:

    Thread receiveThread = new Thread(new Runnable() {
            @Override
            public void run() {
                while(threadsActive) {
                    try {
                        Thread.sleep(200);  //Idle time if no one´s connected
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }

                    synchronized(connectedInputStreams) {
                        for(int i = 0; i < connectedInputStreams.size(); i++) { //checks all clients for messages
                            try {
                                if(connectedInputStreams.get(i).ready()) {      
                                    String recievedMsg = connectedInputStreams.get(i).readLine();

                                    synchronized(recievedData) {
                                        recievedData.append(recievedMsg);
                                    }
                                    if(isHost) {
                                        sendAllExceptOne(recievedMsg, i);
                                    }
                                }else {
                                }
                            } catch (java.net.SocketException e) {
                                disconnectClient(i);
                            } catch (IOException e) {
                                e.printStackTrace();

                            }
                        }
                    }
                }
            }
        });

And another one from the accessing Method in NetworkBridge class:

Thread manageTraffic = new Thread(new Runnable() {
        private ArrayList<PlayerEnemie> enemies = new ArrayList<PlayerEnemie>();

        @Override
        public void run() {
            while(threadsActive) {
                synchronized(recievedData) {
                                                        //Example.: join@:192.168.178.21:21:xmobx
                    if(recievedData.length() != 0) {
                        String[] operators = recievedData.toString().split("@");

                        for(String operator : operators) {          //join:192.168.178.21:21:xmobx
                            String[] infos = operator.split(":");

                            if(!operator.equals("")) {
                                switch(infos[0]) {
                                case "join": playerJoined(infos[1], infos[2]); break;
                                case "move": playerMoved(infos[1], infos[2], infos[3]); break;
                                case "leave": clientLeft(infos[1]); break;
                                case "place": blockPlaced(infos[1], infos[2]); break;
                                case "destroy": blockDestroyed(infos[1], infos[2]); break;
                                case "chat": displayMessage(infos[1], infos[2], infos[3]); break;
                                default:
                                    System.out.println("Unknown NetworkOperator: " + operator);
                                }
                            }
                        }
                        recievedData.delete(0, recievedData.length());

                    }
                }
            }
        }

I know it´s a very simple and maybe stupid way of networkcommunication and it´s not really cheating safe at all, but it should just work. Some tipps for the future would be useful.Thanks.

EazyOrNot
  • 1
  • 1
  • Take a look at http://stackoverflow.com/questions/2340106/what-is-the-purpose-of-flush-in-java-streams... It can help a bit – DarkV1 Dec 29 '16 at 22:03
  • you are synchronizing both thread classes on the same variable `recievedData` which is not shown in your code. is it the same instance for both/all threads? – Timothy Truckle Dec 29 '16 at 22:07
  • I suggest having one thread reading and writing to each socket connection. Trying to share socket connections this way can result in one socket connection slowing another if you are not careful. – Peter Lawrey Dec 29 '16 at 22:16
  • @Timothy Truckle: Yeah, it´s the same variable for both threads. – EazyOrNot Dec 29 '16 at 22:26
  • @PeterLawrey: So what can I do to avoid these problematic sharing? – EazyOrNot Dec 29 '16 at 22:29
  • @EazyOrNot then you basically have the threads waiting on each other which make the purpose of threads obsolete some how... – Timothy Truckle Dec 29 '16 at 22:29
  • hmm okay, if sharing the same StringBuilder reference with two threads is not the right way, how can i pass my data from the networkSupport to my other NetworkBridge Thread instance? – EazyOrNot Dec 29 '16 at 22:42
  • A simple model is an input reading thread and an output writing thread. Your output writing thread reads a queue of messages and writes them to the socket. The input thread reads messages and processes them. Any thread e.g. any reading thread, can add a message to the queue for any socket at any time. Once you get more advanced and you have thousands of connections, you can look at using NIO (or using a library which does this for you e.g. netty) – Peter Lawrey Dec 30 '16 at 10:15
  • Thank you for this information, tomorrow I´ll try it out. – EazyOrNot Dec 31 '16 at 19:50

0 Answers0