Question

I'm making a multiplayer game in java, and I'm really have some issues here. For some reason, my Datagram socket will stop receiving packets set from the client even though according to the console, it recieved them perfectly fine before. I don't know much about networking or programming with sockets, so this has me stumped.

Here's my code:

Server:

package server;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicInteger;

import shared.BaseEntity;
import shared.MethodNotOverridenException;
import shared.Packet;
import shared.Player;

public class S_GameLoop implements Runnable{
    //Constants
    private static final int TICKS_PER_SECOND = 25;
    private static final int TICKS_TO_SKIP = 1000 / TICKS_PER_SECOND;
    private static final int MAX_FRAMESKIP = 5;
    private static final int SPAWN_COORD_X = 50;
    private static final int SPAWN_COORD_Y = 50;

    private Vector<S_Client> ClientList;
    private Map<Integer, BaseEntity> EntityMap;
    private AtomicInteger IDGenerator;

    private boolean gameIsRunning = true;
    private DatagramSocket socket;
    byte[] recieveData = new byte[1024];
    byte[] prevRecieveData = new byte[1024];

    private int port;
    private int loops;

    public S_GameLoop(int port) {
        ClientList = new Vector<S_Client>();
        this.port = port;
        IDGenerator = new AtomicInteger();
        EntityMap = new HashMap<Integer, BaseEntity>();
    }

    private void Init() throws SocketException {
        System.out.println("INIT");
        socket = new DatagramSocket(port);
        System.out.println("[Server] Create listen server on " + socket.getLocalAddress().getHostAddress() + " on port " + socket.getLocalPort());
        socket.setSoTimeout(0);
    }

    private void Running() {
        System.out.println("S_GameLoop staring");
        long nextGameTick = System.currentTimeMillis();

        DatagramPacket recievePacket = new DatagramPacket(recieveData, recieveData.length);

        //GameLoop goes here
        while(gameIsRunning) {
            loops = 0;

            //Receive the data
            try {
                socket.receive(recievePacket);
            } catch (IOException e1) {
                e1.printStackTrace();
            }

            while(System.currentTimeMillis() > nextGameTick && loops < MAX_FRAMESKIP) {
                try {
                    Update(recievePacket);
                } catch (MethodNotOverridenException | IOException e) {
                    System.err.println(e);
                }

                nextGameTick += TICKS_TO_SKIP;
                loops++;
            }

            nextGameTick += TICKS_TO_SKIP;
            loops++;

            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void Update(DatagramPacket recievePacket) throws IOException, MethodNotOverridenException {
        if(prevRecieveData != recieveData) {
            parseData(formatData(recievePacket.getData()), recievePacket);
            prevRecieveData = recieveData;
        } else {
            return;
        }
    }

    public static Packet formatData(byte[] data) {
        try {
            if(data[1] == 0);
            String tag = new String(Arrays.copyOfRange(data, 1, 8));
            System.out.println("[Server] Recieved packet " + data[0] + " " + new String(tag));
            return new Packet(data[0],tag.getBytes(), Arrays.copyOfRange(data, 8, data.length));
        } catch (ArrayIndexOutOfBoundsException e) {
            return new Packet((byte)0, new byte[0], new byte[0]);
        }
    }

    private void parseData(Packet p, DatagramPacket recievePacket) throws IOException, MethodNotOverridenException {
        if(p.getTag() == new byte[0]) {
            System.out.println("[Server] Recieved NULL packet");
            return;
        }
        switch (p.getTagAsString()) {
            case "LGN_RQS": System.out.println("[Server] Login Request Recieved");
                            //Login was accepted
                            //Create a Client ref, and add it to the vector
                            S_Client newClient = new S_Client(recievePacket.getAddress(), recievePacket.getPort());
                            ClientList.add(newClient);

                            //Create a player and add it to Entity list
                            Player newPlayer = new Player(IDGenerator.getAndIncrement(), ClientList.indexOf(newClient));
                            EntityMap.put(newPlayer.getEntID(), newPlayer);
                            System.out.println("[Server] Created new Player with EID " + newPlayer.getEntID() + " and CID " + newPlayer.getCID());
                            //Send reply to Client that is logging in
                            sendData(new Packet((byte)2, "LGN_ACP".getBytes(), ("CID;" + ClientList.indexOf(newClient) + ";EID;" + newPlayer.getEntID()).getBytes()).getBytes(), newClient.getIp(), newClient.getPort());
                            //New Entity was created
                            //sendData(newPlayer.onCreate(this));
                            break;

            case "HND_SHK": System.out.println("[Server] Handshake Recieved");

                            String fdata = new String(p.getData());
                            String[] data = fdata.split(";");

                            //Get client by client ID
                            S_Client c = ClientList.get(Integer.parseInt(data[1]));
                            c.setUsername(data[3]);
                            System.out.println("[Server] Set Client " + data[1] + "'s username to " + data[3]); 
                            //Now spawn the player
                            sendData(new Packet((byte)9, "PLR_SPW".getBytes(), ("CID;" + data[1] + ";X;" + SPAWN_COORD_X + ";Y;" + SPAWN_COORD_Y).getBytes()).getBytes());
                            break;
        }
    }

    public String[] byteArrayToStringArray(byte[] b) {
        String fdata = new String(b);
        return fdata.split(";");
    }

    public void createEntity(BaseEntity be) throws MethodNotOverridenException, IOException {
        int ID = IDGenerator.incrementAndGet();
        be.setEntID(ID);
        EntityMap.put(ID, be);
        sendData(be.onCreate(this));
    }

    public void sendData(byte[] sendData, InetAddress IP, int port) throws IOException {
        System.out.println("[Server] Send packet " + sendData[0] + " " + new String(Arrays.copyOfRange(sendData, 1, 8)));
        DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IP, port);
        socket.send(sendPacket);
    }

    public void sendData(byte[] sendData) throws IOException {
        for (S_Client entry : ClientList) {
            sendData(sendData, entry.getIp(), entry.getPort());
        }
    }

    @Override
    public void run() {
        try {
            Init();
            Running();
        } catch (SocketException e) {
            System.err.println(e);
        } catch (IOException e) {
            System.err.println(e);
        }
    }
}

Client:

package client;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.Arrays;
import java.util.Vector;

import shared.BaseEntity;
import shared.Packet;
import shared.Player;

public class C_GameLoop {
    //How fast should the game update?
    private static final int TICKS_PER_SECOND = 25;
    //How many ticks should be skipped in order to run it at that speed?
    //If it runs faster, then the Render() will be called more often
    private static final int TICKS_TO_SKIP = 1000 / TICKS_PER_SECOND;
    //How many times should you skip rendering, if you have to?
    private static final int MAX_FRAMESKIP = 5;

    RenderCanvas rc;

    InetAddress ServerIP;
    private DatagramSocket socket;
    private int port;
    private boolean connectedToServer = false;
    private boolean waitForData = false;
    private String username = "Dummy";
    byte[] sendPacket;

    Vector<BaseEntity> RenderList;
    Player player;


    int fps = 0;

    public C_GameLoop(RenderCanvas rc){
        this.rc = rc;
        RenderList = new Vector<BaseEntity>();
    }


    public boolean Connect(InetAddress ServerIP, int port) throws IOException {
        this.port = port;
        this.ServerIP = ServerIP;
        socket = new DatagramSocket();
        socket.setSoTimeout(4000);

        DatagramPacket recieveData = new DatagramPacket(new byte[1024], new byte[1024].length);

        System.out.println("[Client] Connecting to: " + ServerIP.getHostAddress() + ":" + port);
        //Send a login request
        sendData(new Packet((byte)1, "LGN_RQS".getBytes()).getBytes());
        int retries = 0;

        //Start the connect loop
            while(!connectedToServer) {
                try {
                    socket.receive(recieveData);
                    waitForData = false;
                    parseData(formatData(recieveData.getData()));
                    //recieveData.setData(new Packet((byte)0, new byte[0], new byte[0]).getBytes());
                } catch (SocketTimeoutException e) {
                    if(waitForData = true && retries <= 4) {
                        System.out.println("[Client] Failed to recieve response from server, retrying");
                        parseData(formatData(recieveData.getData()));
                        retries++;
                    } else {
                        System.out.println("[Client] Failed to Connect to the server!");
                        return false;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        return true;
    }

    public void sendData(byte[] data) throws IOException {
        System.out.println("[Client] Sent packet " + data[0] + " " + new String(Arrays.copyOfRange(data, 1, 8)));
        DatagramPacket sendPacket = new DatagramPacket(data, data.length, ServerIP, port);
        socket.send(sendPacket);
        waitForData = true;
    }

    private void parseData(Packet p) throws IOException {
        switch (p.getTagAsString()) {
            case "LGN_ACP": System.out.println("[Client] Login Accepted");
                            //Get the data needed to create a new player from the packet
                            String fdata = new String(p.getData());
                            String[] data = fdata.split(";");
                            Player player = new Player(Integer.parseInt(data[1]), Integer.parseInt(data[3].trim()));
                            //Add it to the render list
                            this.player = player;
                            rc.getCamera().addDrawableEntity(player);

                            System.out.println("[Client] Player created with CID " + data[1] + " and EID " + data[3]);

                            //Send the handshake
                            System.out.println("[Client] Finshing Handshake...");
                            sendData(new Packet((byte)4, "HND_SHK".getBytes(), ("CID;" + player.getCID() + ";Username;" + username).getBytes()).getBytes());
                            break;
            case "PLR_SPW": System.out.println("[Client] Spawn Recieved");
                            //Get the coords
                            String[] spawn_data = byteArrayToStringArray(p.getData());
                            this.player.setX(Integer.parseInt(spawn_data[3]));
                            this.player.setY(Integer.parseInt(spawn_data[5].trim()));

                            sendData(new Packet((byte)0, "KEP_ALV".getBytes()).getBytes());
                            break;

        }
    }

    public String[] byteArrayToStringArray(byte[] b) {
        String fdata = new String(b);
        return fdata.split(";");
    } 

    /*
     * Formats data into a packet
     */
    public static Packet formatData(byte[] data) {
        try {
            if(data[1] == 0);
            String tag = new String(Arrays.copyOfRange(data, 1, 8));
            System.out.println("[Client] Recieved packet " + data[0] + " " + new String(tag));
            return new Packet(data[0],tag.getBytes(), Arrays.copyOfRange(data, 8, data.length));
        } catch (ArrayIndexOutOfBoundsException e) {
            return new Packet((byte)0, new byte[0], new byte[0]);
        }
    }
}

Console output when running code:

 INIT
[Server] Create listen server on 0.0.0.0 on port 4334
S_GameLoop staring
[Client] Connecting to: 127.0.0.1:4334
[Client] Sent packet 1 LGN_RQS
[Server] Recieved packet 1 LGN_RQS
[Server] Login Request Recieved
[Server] Created new Player with EID 0 and CID 0
[Server] Send packet 2 LGN_ACP
[Client] Recieved packet 2 LGN_ACP
[Client] Login Accepted
[Client] Player created with CID 0 and EID 0
[Client] Finshing Handshake...
[Client] Sent packet 4 HND_SHK
[Client] Failed to recieve response from server, retrying
(Same lines as previous 6 just repeat 4 times)
[Client] Failed to Connect to the server!

Any Ideas?

Was it helpful?

Solution

It looks like your Server class is designed to be used as the Runnable of some worker thread.

I suspect that the problem is that the run() method is dying due to an uncaught exception, and that the worker thread is simply terminating.

I recommend that you configure a default uncaught exception handler to (at least) log the stack trace for the fatal exception. Refer to the Thread javadocs for details.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top