[KryoNet] Networking only works on LAN?

Hi everyone.

I’m making a rpg game with plain Java2D and I’m using KryoNet library to do the networking. Now when I test the game on the same computer, everything works fine, clients send data to server and server sends that to other clients. But when I try to test it with my friend who is on other computer the connection fails every time. We have tried Hamachi but it’s the same. Do you guys have any similar experiences, fixes or ideas on what is wrong?

Here are my GameClient and GameServer classes (Sorry for messy code, I’m gonna clean it later I promise :P) if they are any help at all.

GameClient


package net;

import Game.gameManager;
import Gui.Ginterface;
import Gui.UI;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryonet.Client;
import com.esotericsoftware.kryonet.Connection;
import com.esotericsoftware.kryonet.Listener;
import java.awt.Point;
import java.io.IOException;

public class GameClient {
    
    private Client client = new Client();
    private GamePackage pack;
    private Ginterface inface;
    private gameManager mgm;
    private String username, hostAddress;
    private UI ui;
    
    public void voidSetHostAdd(String a) {
        hostAddress = a;
    }
    
    public void setUi(UI ui) {
        this.ui = ui;
    }
    
    public void setInface(Ginterface inface) {
        this.inface = inface;
    }
    
    public void setMgm(gameManager mgm) {
        this.mgm = mgm;
    }
    
    public void setUsername(String username) {
        this.username = username;
        sendJoinMSG();
    }
    
    public GameClient(String a) {
        hostAddress = a;
        new Thread(client).start();
        Kryo kryo = client.getKryo();
        kryo.register(byte[].class);
        kryo.register(GamePackage.class);
        try {
            client.connect(30000, hostAddress, 54555, 54777);
        } catch (IOException e) {
        }
        client.addListener(new Listener() {
            @Override
            public void received(Connection connection, Object object) {
                if (object instanceof GamePackage) {
                    GamePackage pack = (GamePackage) object;
                    String[] dataArray = readData(pack.getData()).split(",");
                    
                    //Process the incoming packages


                    if ("-1".equals(dataArray[0])) {
                        ui.newNick();
                    }
                    if ("-2".equals(dataArray[0])) {
                        sendJoinMSG();
                    }
                    if ("00".equals(dataArray[0]) && dataArray.length > 1) {
                        inface.addMsg(pack.getSenderName() + ": " + dataArray[1]);
                    }
                    if ("01".equals(dataArray[0])) {
                        if (!pack.getSenderName().equals(username) && !mgm.hasMPP(pack.getSenderName())) {
                            inface.addMsg("> " + pack.getSenderName() + " connected.");
                            mgm.addMPPlayer(pack.getSenderName(), new Point(300, 300));
                            String data = "05";
                            pack = new GamePackage(data.getBytes(), username);
                            client.sendTCP(pack);
                        }
                    }
                    if ("05".equals(dataArray[0])) {
                        if (!pack.getSenderName().equals(username) && !mgm.hasMPP(pack.getSenderName())) {
                            System.out.println("05");
                            inface.addMsg("> " + pack.getSenderName() + " connected.");
                            mgm.addMPPlayer(pack.getSenderName(), new Point(300, 300));
                        }
                    }
                    if ("02".equals(dataArray[0])) {
                        inface.addMsg("> " + pack.getSenderName() + " disconnected.");
                        mgm.removeMPPlayer(pack.getSenderName());
                    }
                    if ("03".equals(dataArray[0]) && dataArray.length >= 2) {
                        if (mgm.hasMPP(pack.getSenderName())) {
                            mgm.getMPP(pack.getSenderName()).setPosition(new Point(Integer.parseInt(dataArray[1]), Integer.parseInt(dataArray[2])));
                        }
                    }
                    if ("07".equals(dataArray[0])) {
                        inface.setIsAdmin(true);
                    }
                    if ("08".equals(dataArray[0])) {
                        inface.setIsAdmin(false);
                    }
                    if ("09".equals(dataArray[0])) {
                        inface.addMsg("You have been kicked from the game.");
                        mgm.cleanAll();
                        sendDisconnect();
                    }
                    if ("26".equals(dataArray[0]) && dataArray.length >= 2) {
                        if (mgm.hasMPP(pack.getSenderName())) {
                            mgm.getMPP(pack.getSenderName()).setPosition(new Point(Integer.parseInt(dataArray[1]), Integer.parseInt(dataArray[2])));
                            mgm.getMPP(pack.getSenderName()).setFrame(Integer.parseInt(dataArray[3]));
                        }
                    }
                }
            }
        });
        
        
        
    }

     //Sending packages
    
    public String readData(byte[] data) {
        String message = new String(data).trim();
        return message;
    }
    
    public void sendMSG(String msg) {
        String data = "00" + "," + msg;
        pack = new GamePackage(data.getBytes(), username);
        client.sendTCP(pack);
    }
    
    public void sendJoinMSG() {
        String data = "01";
        pack = new GamePackage(data.getBytes(), username);
        client.sendTCP(pack);
    }
    
    public void sendDisconnect() {
        String data = "02";
        pack = new GamePackage(data.getBytes(), username);
        client.sendTCP(pack);
        client.close();
    }
    
    public void sendPosT() {
        String data = "03" + "," + ((int) mgm.getPlayer().getPosition().getX()) + "," + ((int) mgm.getPlayer().getPosition().getY());
        pack = new GamePackage(data.getBytes(), username);
        client.sendTCP(pack);
    }
    
    public void subNick(String n) {
        username = n;
        String data = "04";
        pack = new GamePackage(data.getBytes(), username);
        client.sendTCP(pack);
    }
    
    public void sendPrivateMSG(String msg, String to) {
        String data = "06" + "," + to + "," + msg;
        pack = new GamePackage(data.getBytes(), username);
        client.sendTCP(pack);
    }
    
    public void sendAdminTo(String who) {
        String data = "07," + who;
        pack = new GamePackage(data.getBytes(), username);
        client.sendTCP(pack);
    }
    
    public void removeAdminFrom(String who) {
        String data = "08," + who;
        pack = new GamePackage(data.getBytes(), username);
        client.sendTCP(pack);
    }
    
    public void kickPlayer(String who) {
        String data = "09," + who;
        pack = new GamePackage(data.getBytes(), username);
        client.sendTCP(pack);
    }
    
    public void sendPosU() {
        String data = "26" + "," + ((int) mgm.getPlayer().getPosition().getX()) + "," + ((int) mgm.getPlayer().getPosition().getY() + "," + mgm.getPlayer().getPg().getFrames());
        pack = new GamePackage(data.getBytes(), username);
        client.sendUDP(pack);
    }
}


GameServer


package net;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryonet.Connection;
import com.esotericsoftware.kryonet.Listener;
import com.esotericsoftware.kryonet.Server;
import java.io.IOException;
import java.util.HashMap;
import java.util.Random;
import java.util.Scanner;

public class GameServer {

    private Server server;
    private static Scanner scan = new Scanner(System.in);
    private HashMap<Connection, String> users = new HashMap<>();
    private HashMap<String, Connection> rev = new HashMap<>();

    public GameServer() {
 

        server = new Server();
        Random rand = new Random();
        new Thread(server).start();
        Kryo kryo = server.getKryo();
        kryo.register(byte[].class);
        kryo.register(GamePackage.class);
        try {
            server.bind(54555, 54777);
        } catch (IOException e) {
        }
        final byte[] someData = new byte[10];
        for (int i = 0; i < 10; i++) {
            someData[i] = (byte) rand.nextInt(5);
        }
        server.addListener(new Listener() {
            @Override
            public void received(Connection connection, Object object) {

                if (object instanceof GamePackage) {

                    GamePackage pack = (GamePackage) object;

                    String[] dataArray = readData(pack.getData()).split(",");

                    if (Integer.parseInt(dataArray[0]) <= 5 && Integer.parseInt(dataArray[0]) > 0) {
                        server.sendToAllExceptTCP(connection.getID(), object);
                    } else if (Integer.parseInt(dataArray[0]) == 0) {
                        server.sendToAllTCP(object);
                    }
                    if (Integer.parseInt(dataArray[0]) == 6 && dataArray.length >= 3) {
                        if (rev.containsKey(dataArray[1])) {
                            GamePackage packN = new GamePackage(("00," + dataArray[2]).getBytes(), pack.getSenderName());
                            server.sendToTCP(rev.get(dataArray[1]).getID(), packN);
                        }
                    }
                    if (Integer.parseInt(dataArray[0]) == 7) {
                        if (rev.containsKey(dataArray[1])) {
                            GamePackage packN = new GamePackage(("07,").getBytes(), pack.getSenderName());
                            server.sendToTCP(rev.get(dataArray[1]).getID(), packN);
                        }
                    }
                    if (Integer.parseInt(dataArray[0]) == 8) {
                        if (rev.containsKey(dataArray[1])) {
                            GamePackage packN = new GamePackage(("08,").getBytes(), pack.getSenderName());
                            server.sendToTCP(rev.get(dataArray[1]).getID(), packN);
                        }
                    }
                    if (Integer.parseInt(dataArray[0]) == 9) {
                        if (rev.containsKey(dataArray[1])) {
                            GamePackage packN = new GamePackage(("09,").getBytes(), pack.getSenderName());
                            server.sendToTCP(rev.get(dataArray[1]).getID(), packN);
                        }
                    }
                    if (Integer.parseInt(dataArray[0]) == 1) {
                        if (users.containsValue(pack.getSenderName())) {
                            pack = new GamePackage("-1".getBytes(), "SERVER");
                            server.sendToTCP(connection.getID(), pack);
                        } else {
                            users.put(connection, pack.getSenderName());
                            rev.put(pack.getSenderName(), connection);
                        }
                    }
                    if (Integer.parseInt(dataArray[0]) == 4) {
                        if (users.containsValue(pack.getSenderName())) {
                            pack = new GamePackage("-2".getBytes(), "SERVER");
                            server.sendToTCP(connection.getID(), pack);
                        } else {
                            users.put(connection, pack.getSenderName());
                            rev.put(pack.getSenderName(), connection);
                            String data = "01";
                            pack = new GamePackage(data.getBytes(), pack.getSenderName());
                            server.sendToAllExceptTCP(connection.getID(), pack);
                        }
                    }
                    if (Integer.parseInt(dataArray[0]) >= 26) {
                        server.sendToAllUDP(object);
                    }
                }
            }
        });
    }

    public String readData(byte[] data) {
        String message = new String(data).trim();
        return message;
    }

    public void sendMSG(String msg) {
    }
}


And the GamePackage class


package net;

public class GamePackage {

	private byte[] data;
	private String senderName;
	
	public GamePackage() {
		
	}

	public GamePackage(byte[] data, String name) {
		this.data = data;
		senderName = name;
	}

	public byte[] getData() {
		return data;
	}

	public String getSenderName() {
		return senderName;
	}
}


Have you port forwarded your program? I’ve never used Hamachi so I don’t know whats wrong with that.

Well I quess I should try port forwarding, but Hamachi should work just the same so I’m not sure if that is causing my problem. I’ll probably try forwarding tomorrow just to be sure, thanks for answering! :slight_smile:

No problem :slight_smile: Have you tried running it on local host just to see if it works?
You can always hit the appreciate button on the top right of my post to thank me :wink:

Main post:

[quote]Now when I test the game on the same computer, everything works fine.
[/quote]
I’m not sure if both UDP and TCP work over hamachi (no experience), so hopefully port-forwarding works.
Once, I had this problem in C++ using UDP, but that’s another (unsolved) story…

Isn’t Hamachi a VPN? Would UDP have a problem with it sense it doesn’t require a handshake before sending packets? Honestly, I don’t know if that would affect anything, but maybe that’s it. I haven’t looked over his code too much, but I know that kryonet doesn’t support or advertise their UDP features very widely. So I’d guess OP is using TCP, which shouldn’t have a problem with a VPN.

Please make sure Kryonet is not binding on your loop-back device (127.0.0.1).
You can verify with the command netstat in console:

On windows: netstat -an

On Linux: netstat -ln

You could also try to telnet the TCP port directly (with a software like putty on Windows, telnet command line on Linux/OSX).

Lastly, make sure your firewall is not simply blocking your application port, the first time you run your program a popup window asking a confirmation shows up. It only show once :slight_smile:

HAMACHI is like being in a LAN, no need of port forwarding and both UDP and TCP would work (with extra latency).