Server/Client

So, pleased with me advancement in 3D, I took it upon myself to try some Server/Client communications. I have server/client experience (very little), so this was kind of expected. Basically, my client lags. I have not gotten to large scale test this yet, so right now, that is the only problem. I can show you a video (which I took from an Iphone because I cba to mix video from 2 computers). The silver computer is the computer with the server and the client running, and the black computer is just the client. The block dot is the player.

Video: http://s1375.photobucket.com/user/zFollette/media/IMG_1142_zps903e8b07.mp4.html

Here is some code:

Client class (in the game)

public class Client {

    private Socket socket;
    private final String ip = "192.168.0.8";
    String local;
    private final int port = 43595;
    private BufferedReader br;
    private PrintWriter pw;
    public static final ArrayList<Player> players = new ArrayList<>();

    public Client() throws IOException {
        handleConnection();
    }

    private void handleConnection() throws IOException {
        socket = new Socket();
        socket.connect(new InetSocketAddress(ip, port));
        local = socket.getInetAddress().getHostAddress();
        br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        pw = new PrintWriter(socket.getOutputStream());
        Thread t = new Thread(new Connection());
        t.start();
    }

    public void sendMessage(String message) {
        pw.println(message);
        pw.flush();
    }

    private class Connection implements Runnable {

        @Override
        public void run() {
            String line;

            try {
                while ((line = br.readLine()) != null) {
                    String ip = line.split(": P")[0].trim();
                    if (line.contains("POSITION")) {
                        String[] values = line.replaceAll(ip, "").replaceAll(": POSITION:", "").trim().split(", ");

                        Player p = new Player(ip);
                        p.setX(Float.parseFloat(values[0]));
                        p.setY(Float.parseFloat(values[1]));
                        p.setZ(Float.parseFloat(values[2]));

                        if (!contains(players, ip) && !ip.equals(local)) {
                            players.add(p);
                        }

                        for (int i = 0; i < players.size(); i++) {
                            if (players.get(i).getIp().equals(ip)) {
                                players.set(i, p);
                                break;
                            }
                        }
                    }
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

        private boolean contains(ArrayList<Player> s, String s1) {
            for (int i = 0; i < s.size(); i++) {
                if (s.get(i).getIp().equals(s1)) {
                    return true;
                }
            }
            return false;
        }
    }
}

Server class (seperate program)

public final class Server {

    private ServerSocket server;
    private Socket socket;
    private final int port = 43595;
    private final String ip = "192.168.0.8";
    public static ArrayList<Player> players = new ArrayList<>();

    public Server() throws IOException {
        handleConnection();
    }
    
    private void handleConnection() throws IOException {
        server = new ServerSocket();
        server.bind(new InetSocketAddress(ip, port));

        while (true) {
            socket = server.accept();
            Player player = new Player(socket.getInetAddress().getHostAddress());
            player.setS(socket);
            players.add(player);
            Thread t = new Thread(new ConnectionHandler(socket, player));
            t.start();
        }
    }
}

ConnectionHandler class (part of server)

public class ConnectionHandler implements Runnable {

    Socket s;
    int port = 43595;
    Player p;

    public ConnectionHandler(Socket s, Player p) {
        this.s = s;
        this.p = p;
    }

    @Override
    public void run() {
        try {
            System.out.println("Client: " + s.getInetAddress() + " has connected.");
            BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
            PrintWriter pw;
            String line;

            while (true) {
                while ((line = br.readLine()) != null) {
                    if (line.startsWith("POSITION:")) {
                        String[] values = line.replaceAll("POSITION:", "").trim().split(", ");
                        p.setX(Float.parseFloat(values[0]));
                        p.setY(Float.parseFloat(values[1]));
                        p.setZ(Float.parseFloat(values[2]));
                        
                        ArrayList<Player> ps = Server.players;
                        
                        for (int i = 0; i < ps.size(); i++) {
                            Player p1 = ps.get(i);
                            for (int j = 0; j < ps.size(); j++) {
                                    pw = new PrintWriter(ps.get(j).getS().getOutputStream());
                                    pw.println(p1.getIp() + ": POSITION: " + p1.getX() + ", " + p1.getY() + ", " + p1.getZ());
                                    pw.flush();
                            }
                        }
                    }
                }
            }

        } catch (IOException ex) {
            System.out.println("Client: " + s.getInetAddress() + " has disconnected.");
        }
    }
}

So, I am going to assume my code is a terrible way of doing what I want, because it usually is, lol. But I also have another question. The computer that is lagging is slightly less powerful (intel i5, intel graphics 3000) than the one that is not lagging (intel i7, NVIDIA optimus). Could this be the problem? I ruled it out earlier because the rest of the game (cubes and what not) render fine. Its the the dot.

EDIT: Possible cause, I render the dot in immediate mode.

I don’t see a call to repaint in your code.
There are a few things you could try.
Use DataInput/OutputStream and don’t buffer the streams.
Call Socket.setTcpNoDelay(true); and Socket.setTrafficClass(0x10); before you connect the socket. i.e. between line 16 and 17 in your code.

Well, I guess it is worthy to mention that this is openGL, not swing. However, I will look at your other suggestions.

EDIT: I have no time to test, but the documentation looks promising…

Are you doing any kind of client side prediction? Essentially, you don’t want to wait for the server to confirm your movements.

Gabriel’s series of articles is pretty helpful. This is probably exactly what you want http://gabrielgambetta.com/fpm_live.html

That looks like exactly what I need.

EDIT: I read through it, but I don’t understand how I could effectivly predict the positions of a player, in they game (like most others) I can move up, down, left,right, forward, backward, and anywhere in between. There is no limit to where I can move, therefor making the game un-predictable

No. Read it again. Ask help on specific things.

Ok, how can I predict the next movement if the amount of movements to select from is (for all intents and purposes) unlimited.

Don’t use strings to encode your packet data. Use binary.

You can either choose to prefix each packet with a header (with length and packet id) or use just packet id and fixed length packets, or a mix of both. For example, movement packets should always be the same size, { InputID, Timestamp } but attack packets may be different sized, depending on your game for example.

Do client side prediction, for the local player and for remote players. Do interpolation for remote players to make their movement smooth, and just implement the same movement algorithm on the client as you have on the server, so basically the client moves, server gets an update, moves him, sends the packet back to client, if this movement is old, just discard it otherwise update your local player to server position.

You may need to do lag compensation if you are making a FPS for example. Shooting packets should be sent with the Timestamp and the server can recalculate exactly where the entities were at that timestamp, and apply the shot.

Add them all up. http://www.youtube.com/watch?v=xp6ibuI8UuQ