2015-12-10 3 views
4

Я новичок в StackOverflow lol, но на некоторое время я полагаюсь на этот сайт. У меня есть вопрос относительно созданного мной сервера сокетов Java. При подключении (клиент и сервер) мое приложение создает поток для этого клиента. Это игровой сервер MMORPG ... по крайней мере, пытаюсь быть. С одним игроком он не отстает от этого плохо. С двумя, однако, он начал показывать некоторые лаги ...Сервер Java Socket отстает от двух клиентов

Если бы я был спам слева-направо налево на одном из клиентов и мог нормально перемещаться с другим, другой мог бы чувствовать себя глючным. Я надеюсь получить помощника, так как я потратил более полутора недель, запутанных =) Пришло время попросить о помощи.

Код прост:

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(); 
    } 
} 

Вот как все это началось! На объекте игрока, он выглядит следующим образом:

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 случается статический метод из конечного статического класса. Это глобальный метод, который может вызываться каждым потоком (Может ли это быть причиной отставания ??)

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(), я просто создал простой метод, который conerts шорты в байтах (отправка пакеты буферов через байты к клиенту). Пример, у меня есть около 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; 
} 

Глядя на следующую структуру, любые идеи, почему я быть отстаем?

EDIT: Я думаю, что я улучшил его, установив 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(); 

Из того, что я вижу ... мой «спамить влево/вправо» конец, кажется, отсутствует пакет, посланный сервером.

+0

Я заметил, что messageHandler находится в цикле while. Как часто он вызывается, когда вы спам влево-вправо? Если ваш сервер получает тонну сообщений каждую секунду, которые он должен читать и обрабатывать, это может быть ресурсоемким. – faraza

+0

Он называет один раз влево или вправо. «Int msgid = input.readUnsignedByte()» приостанавливает цикл while, поэтому я могу поместить инструкцию печати внутри, и она только печатает один раз перед остановкой. Когда пользователь нажимает LEFT или RIGHT, он снова печатает на каждую нажатую клавишу/полученное сообщение – AlbertGeno

+0

Можете ли вы поместить println в sendPacketToAllClients, чтобы узнать, как часто это вызвано? – faraza

ответ

0

Проблема решена. =) setTcpNoDelay true сделал трюк. Что касается части, когда я сказал, что мне не хватает пакетов, я на самом деле этого не делал. Два сообщения слились и вошли как одно сообщение. Моя программа только читала первые несколько байтов и игнорировала остальные. Если бы поставить байт впереди, чтобы указать размер сообщения. Как только это было на месте, я установил цикл while, чтобы прочитать его, пока он не сможет больше читать. =) Спасибо всем за то, что помогли мне. Мой первый пост, и это был большой опыт.

+0

Пожалуйста, не делайте этого. Пожалуйста, исправьте реальную проблему, а не скрывайте симптомы, отключив Nagling. Это делает использование сети менее эффективным и приведет к неудовлетворительному поведению, если ваша программа столкнется с крайними проблемами Nagling. Функция отсутствия TCP-протокола существует, чтобы позволить протоколам pre-TCP работать лучше по TCP и не нужно использовать что-то, предназначенное для использования TCP. –

+0

Я думаю, вы правы ... я должен удалить этот ответ? Я имею в виду, что он действительно работает, и производительность хороша. Но я думаю, я должен искать другой ответ. Какие-либо предложения?? = ( – AlbertGeno

+1

Я некоторое время искал вокруг, и есть люди, которые говорят о низкой латентности, отключая его, хорошо для высокой пропускной способности с большой передачей файлов, что позволяет это хорошо, так как алгоритм nagle состоит в том, чтобы отправлять только пакеты полного размера, что приведет к задержке для небольших сообщений из-за времени ожидания. Сообщение, которое я передаю, относительно невелико, наиболее часто встречаются 5 байтов. – AlbertGeno