Java Socket Server滞后于两个客户端

时间:2015-12-10 07:55:33

标签: java multithreading sockets 2d-games

我是StackOverflow的新手lol,但我一直依赖这个网站。我有一个关于我创建的Java套接字服务器的问题。在连接(客户端和服务器)时,我的应用程序为该客户端创建一个线程。这是一款MMORPG游戏服务器......至少是尝试过。对于一名球员来说,它并没有落后于那么糟糕。然而,有两个,它开始显示一些滞后......

如果我要在其中一个客户端上左右 - 左右 - 发送垃圾邮件,并且正常地与另一个客户端一起移动,那么另一个会感到毛病。我希望得到一些助手,因为我已经花了一个半星期的时间纠结了=)这是关于我寻求帮助的时间。

代码很简单:

public static void main(String[] args) throws IOException{
    serverRooms.put(roomNumber, new Room());

    try {
        System.out.println("Starting Server...");
        serverSocket = new ServerSocket(9595, 20);

        System.out.println("Server Started");
        while(run){
            Socket socket = serverSocket.accept();      // Check if we have a connection, otherwise wait

            Player player = new Player(playerCount++, socket, roomNumber);
            new Thread(player).start();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

这是怎么开始的!在Player对象上,它看起来像:

public void run() {
    while(playerIsConnected) {
        try {
            int msgid = input.readUnsignedByte();
            messageHandler(this, msgid);

        } catch (IOException e) {
            System.err.println("Player have signed off");
            playerIsConnected = false;
        }
    }

    // If Player leaves, close socket, and end thread
    try {
        socket.close();
    } catch (IOException e) {
        System.out.println("We got an error while closing a socket on player " + pid + ".");
    }
}

messageHandler碰巧是Final Static类的静态方法。它是一个可以被每个线程调用的全局方法(这可能是滞后的原因吗?)

public final class MessageControl {

public static void messageHandler(Player player, int msgid) throws IOException{
    DataInputStream input = player.getInputStream();
    switch (msgid) {
        case 10:
            byte hspd = (byte) Math.signum(input.readByte());
            byte vspd = (byte) Math.signum(input.readByte());
            byte dir = input.readByte();

            updatePlayerPosition(player);
            byte spd = (byte) (hspd != 0 && vspd != 0 ? player.spd-1 : player.spd);

            // Prepare packet and send to clients
            ByteBuffer buffer = ByteBuffer.allocate(11);
            buffer.put((byte) 10);
            buffer.put(shortToByte_U16(player.pid));
            buffer.put(shortToByte_U16(player.x));
            buffer.put(shortToByte_U16(player.y));
            buffer.put((byte)(hspd*spd));
            buffer.put((byte)(vspd*spd));
            buffer.put((byte)(dir));
            sendPacketToAllClients(player, buffer, true);

            // Update Player info
            player.hspd = (byte) hspd;
            player.vspd = (byte) vspd;
            player.dir = dir;
            player.lastUpdate = System.currentTimeMillis();
        break;
    }
private static void sendPacketToAllClients(Player player, ByteBuffer buffer, boolean includeMe){
    for (Player otherPlayer : player.room.getPlayersInRoom()){
        if (otherPlayer.pid != player.pid || includeMe){
            sendPacketToClient(otherPlayer, buffer);
        }
    }
}
}

关于shortToByte_U16(),我刚刚创建了一个简单的方法,将锥形短路转换为字节(通过字节向客户端发送缓冲区包)。例如,我有大约5个这样的转换,其中包括转换为无符号u16

public static byte[] shortToByte_16(int x){
    short s = (short) x;
    byte[] ret = new byte[2];
    ret[0] = (byte)(s & 0xff);
    ret[1] = (byte)((s >> 8) & 0xff);
    return ret;
}

看看以下结构,为什么我会落后的任何想法?

编辑:我认为通过将setTcpNoDelay设置为true可以对其进行大量改进。当我在我的端子上左/右发垃圾时,似乎仍然存在滞后...我屏幕上的其他播放器看起来很奇怪。

            Socket socket = serverSocket.accept();      // Check if we have a connection, otherwise wait
            socket.setTcpNoDelay(true);  // This helped a lot!!!
            Player player = new Player(playerCount++, socket, roomNumber);
            new Thread(player).start();

从我所看到的......我的"垃圾邮件左/右" end似乎丢失了服务器发送的数据包。

1 个答案:

答案 0 :(得分:0)

问题解决了。 =)setTcpNoDelay true做了伎俩。关于我说我丢失数据包的部分,我实际上没有。这两条消息合并在一起作为一条消息传入。我的程序只读取前几个字节而忽略了其余的字节。不得不在前面放一个字节来表示消息的大小。一旦到位,我设置了一个while循环来读取它直到它不能再读取。 =)感谢大家帮助我。我的第一篇文章,这是一次盛大的经历。