2009-12-18 2 views
0

Хорошо, Итак, я работаю над игрой (например, даже не с альфой), и это, предположительно, битва 1 на 1, где один человек принимает сервер, а другой подключается. Но сейчас код слишком отсталый, чтобы что-либо сделать. Может кто-то взглянуть на него и рассказать мне, как ускорить его? PS: Я также использую Slick2D lib.Может кто-нибудь помочь мне ускорить мой netcode в Java?

Сервер:

import java.net.*; 
import java.io.*; 

public class SlickServer{ 
    public static void main(String[] args) throws IOException { 

     int MAX_PLAYERS = 3; 
     int playerNum = 0; 
     Player[] players = new Player[MAX_PLAYERS]; 
     players[0] = new Player(25,25); 
     players[1] = new Player(125,125); 
     players[2] = new Player(225,225); 
     ServerSocket serverSocket = new ServerSocket(4444); 
     boolean listening = true; 

     while(listening){ 
      System.out.println("Waiting to connect with: " + playerNum); 
      new ClientThread(serverSocket.accept(), players, playerNum).start(); 
      //stops here. 
      System.out.println("Connected with: " + playerNum + " Now incrementing"); 
      playerNum++; 
      System.out.println("Incremented to: " + playerNum); 
     } 



     serverSocket.close(); 
     System.exit(0); 
    } 
} 

Сервер Тема:

import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.net.*; 
import java.io.*; 

public class ClientThread extends Thread implements Runnable{ 
    Socket acceptedSocket; 
    Player[] players; 
    int playerNum; 

    public ClientThread(Socket acceptedSocket, Player[] players, int playerNum){ 
     super("ClientThread"); 
     this.acceptedSocket = acceptedSocket; 
     this.players = players; 
     this.playerNum = playerNum; 
    } 

    public void run(){ 
     try{ 

      Socket clientSocket = acceptedSocket; 
      System.out.println("Accepted. Now creating I/O."); 
      ObjectInputStream in = new ObjectInputStream(clientSocket.getInputStream()); 
      ObjectOutputStream out = new ObjectOutputStream(clientSocket.getOutputStream()); 
      System.out.println("I/O with: " + playerNum + " working."); 
      out.writeInt(playerNum); 
      out.flush(); 

      while(true){ 
       if(playerNum == 0){ 
        players[0].x = in.readInt(); 
        players[0].y = in.readInt(); 
        out.writeInt(players[1].x); 
        out.writeInt(players[1].y); 
        out.flush(); 
       } 

       else if(playerNum == 1){ 
        players[1].x = in.readInt(); 
        players[1].y = in.readInt(); 
        out.writeInt(players[0].x); 
        out.writeInt(players[0].y); 
        out.flush(); 
       } 

       else if(playerNum == 2){ 
        players[2].x = in.readInt(); 
        players[2].y = in.readInt(); 
        out.writeInt(players[0].x); 
        out.writeInt(players[0].y); 
        out.flush(); 
       } 
      } 

     } 

     catch(Exception e){ 
      e.printStackTrace(); 
      System.exit(1); 
     } 


    } 


} 

Клиент:

import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.net.Socket; 

import org.newdawn.slick.AppGameContainer; 
import org.newdawn.slick.BasicGame; 
import org.newdawn.slick.GameContainer; 
import org.newdawn.slick.Graphics; 
import org.newdawn.slick.Image; 
import org.newdawn.slick.Input; 
import org.newdawn.slick.SlickException; 

import java.io.*; 
import java.net.*; 


public class SlickClient extends BasicGame{ 

    int MAX_PLAYERS = 3; 
    int playerNum = 0; 
    Player[] players; 
    ClientThread ct; 

    int serverDelay = 15; 

    public SlickClient() 
    { 
     super("Client"); 
    } 

    @Override 
    public void init(GameContainer gc) 
      throws SlickException { 
     try{ 
      players = new Player[MAX_PLAYERS]; 
      players[0] = new Player(25,25); 
      players[1] = new Player(125,125); 

      ct = new ClientThread(players); 
      ct.start(); 
      ct.setPriority(Thread.MAX_PRIORITY); 

      playerNum = ct.playerNum; 
     } 

     catch(Exception e){ 
      e.printStackTrace(); 
     } 

    } 

    @Override 
    public void update(GameContainer gc, int delta) 
      throws SlickException 
    { 
     Input input = gc.getInput(); 

     if(input.isKeyDown(Input.KEY_A)) 
     { 
      players[playerNum].x-=5; 
     } 

     if(input.isKeyDown(Input.KEY_D)) 
     { 
      players[playerNum].x+=5; 
     } 

     if(input.isKeyDown(Input.KEY_W)) 
     { 
      players[playerNum].y-=5; 
     } 

     if(input.isKeyDown(Input.KEY_S)) 
     { 
      players[playerNum].y+=5; 
     } 



    } 

    public void render(GameContainer gc, Graphics g) 
      throws SlickException 
    { 
     g.fillRect(players[0].x, players[0].y, 50, 50); 
     g.fillRect(players[1].x, players[1].y, 50, 50); 

    } 

    public static void main(String[] args) 
      throws SlickException 
    { 
     AppGameContainer app = 
      new AppGameContainer(new SlickClient()); 

     app.setAlwaysRender(true); 
     app.setTargetFrameRate(30); 
     app.setDisplayMode(800, 600, false); 
     app.start(); 
    } 
} 

class ClientThread extends Thread implements Runnable{ 
    Socket socket; 
    Player[] players; 
    int playerNum; 
    ObjectOutputStream out; 
    ObjectInputStream in; 

    public ClientThread(Player[] players){ 
     super("ClientThread"); 

     try{ 

      socket = new Socket("98.203.176.196", 4444); 
      out = new ObjectOutputStream(socket.getOutputStream()); 
      in = new ObjectInputStream(socket.getInputStream()); 
      this.players = players; 
      playerNum = in.readInt(); 
      System.out.println(playerNum); 

     } 

     catch(Exception e){ 
      e.printStackTrace(); 
     } 
    } 

    public void run(){ 
     try{ 
      while(true){ 
       if(playerNum == 0){ 
        try{ 
         out.writeInt(players[0].x); 
         out.writeInt(players[0].y); 
         out.flush(); 
         players[1].x = in.readInt(); 
         players[1].y = in.readInt(); 
        } 

        catch(Exception e){ 
         e.printStackTrace(); 
        } 
       } 

       else if(playerNum == 1){ 
        try{ 
         out.writeInt(players[1].x); 
         out.writeInt(players[1].y); 
         out.flush(); 
         players[0].x = in.readInt(); 
         players[0].y = in.readInt(); 
        } 

        catch(Exception e){ 
         e.printStackTrace(); 
        } 
       } 
      } 
     } 

     catch(Exception e){ 
      e.printStackTrace(); 
     } 
    } 
} 
+4

Возможно, вам необходимо либо (а) профилировать приложение и рассказать нам, что такое медленные части, либо (б) спросить, как профилировать приложение. –

ответ

2

Разве это только лаги, когда клиент находится на удаленной машине с сервера? Если да, и у вас есть хорошее время для пинга между ящиками, тогда я собираюсь взять себе в голову и сказать, что вы, возможно, столкнулись с алгоритмом Нагле? Данные, которые вы нажимаете, очень малы (writeInt).

Вы можете попробовать использовать посредник BufferedOutputStream, хотя если вы хотите попробовать быстрое исправление, вы можете просто попробовать отключить Nagle на своих сокетах.

Socket.setTcpNoDelay (true);

+0

Это нормально, если у меня есть сокет, подключаемый к «localhost», но если у меня он установлен на мой IP, он будет отставать. набор без задержки помог немного. – William

1

Вы пробовали использовать что-то другое, чем ObjectOutputStream и ObjectInputStream отправлять и получать данные? Использование этих методов предполагает сериализацию и десериализацию объектов, и кажется, что (только догадка), что использование DataOutputStream может быть быстрее.

+0

Вы имели в виду DataInputStream и DataOutputStream, а не ByteArrayOutputStream, поскольку BAOS не будет на самом деле ничего не делать с данными? –

+0

Ой, да, это то, о чем я думал, спасибо. –

+0

Или попробуйте написать собственные методы сериализации и десериализации, которые могут оказаться намного быстрее (имейте в виду проблемы с версиями, то есть старая версия должна быть совместима с новыми версиями при чтении данных). Для получения более подробной информации: http://code.google.com/p/thrift-protobuf-compare/wiki/BenchmarkingV2 и http://stackoverflow.com/questions/647779/high-performance-serialization-java-vs -google-protocol-buffers-vs – Kounavi

1

Ну код, который вы предоставляете, является неполным ... Я собирался сделать это, а затем проведу вас, как это сделать, чтобы я мог быть уверен в том, что вы увидите ... однако мы будем работать с тем, что у нас есть ,

1) Запустите его на одном компьютере как для клиента, так и для сервера - все еще медленно? 2) Ping между машинами и посмотреть, как скорость 3) профиль приложения.

# 1 помогает понять, является ли это сетевой проблемой. И клиент, и сервер на одном компьютере устраняют сеть.

# 2 помогает понять, является ли это сетевой проблемой. Если ping плохой, игра будет медленной.

# 3 сложнее, но даст вам результаты того, где в вашем коде это медленно.

В профиле взгляните на Visual VM (или если вы используете netbeans, просто профиль его там ... eclipse, вероятно, тоже имеет что-то тоже, возможно, как плагин).

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

1

Хммм, несколько вещей, которые вы можете попробовать сразу же, но это потребует некоторой работы, чтобы делать то, что вы хотите.

Во-первых, как ваш клиент, так и ваш сервер находятся в очень плотных петлях. Обычно цикл, как вы используете, должен спать в течение минимального промежутка времени на каждом проходе, чтобы петля не потребляла слишком много CPU, ничего не делая.

Во-вторых, вы, вероятно, должны использовать неблокирующий ввод-вывод (проверьте наличие ввода от каждого клиента, прежде чем пытаться его прочитать).

И, наконец, если вы не хотите приступить к учебному упражнению в отношении Java-сетей или если у вас нет конкретных целей, требующих нестандартного протокола связи, вы можете захотеть использовать структуру сервера, которую вы можете просто расширить. Простым способом сделать это будет создание вашей серверной части с Jetty или Tomcat и использование Apache HTTPClient для вашей клиентской стороны.

Если вы решили остаться с выделенным сервером, простые серверные рамки в книге Core Java или в книге Java Networking (O'Reilly) предоставят вам лучшую базу.

Надеюсь, что это поможет.

1

Это зависит от того, почему это медленно. Вот несколько предложений:

  1. Используйте только неблокирующие устройства ввода-вывода. Как специализация этого правила, никогда не используйте RPC.
  2. Рассмотрите возможность выполнения клиентского прогнозирования, когда это необходимо. Прогнозирование на стороне клиента предполагает, что то, что клиент хочет сделать, будет в порядке и нарисовано на клиенте, как будто все в порядке. Большинство, если не все сетевые игры, используют это.
  3. Примите, что у вас нет «синхронизированного» состояния между вашими игроками в режиме реального времени. Этого просто не случится.

Кроме того, определите, что вы подразумеваете под «получает лагги». Вы имеете в виду, что код дает плохие рамки? Что требуется, чтобы пройти регистрацию? Это будет первым шагом к оптимизации.

И удачи. Получение игровой игры, которая будет реагировать на сеть, будет чем-то трудным делом, даже для профессиональных разработчиков, имеющих опыт программирования в сетевых играх. Вам, вероятно, потребуется изменить свой игровой дизайн в какой-то степени, чтобы скрыть отставание - некоторые вещи просто невозможны по сети.

1

Если вы хотите, вы можете попробовать использовать сокеты дейтаграмм. Если базовый пакет будет удален, он просто уйдет, но поскольку вы просто обновляете позицию, все должно быть хорошо.

Смежные вопросы