2016-04-24 8 views
-1

私はマルチプレイヤーゲームを作成しています。マルチプレイヤーゲームは、各クライアント用に新しいスレッドを作成し、入力ストリームと出力ストリームを介して文字列のソケットを待ち受けます。クライアント側では、メインのゲームスレッドとは別のスレッドもありますが、これはサーバーに2回の文字列を1秒間に60回送信して、何を起こそうとしているかのキーになります。クライアント側で「一般的な更新」(コードRP)を要求すると、サーバーはエンティティ配列のサイズをOKにして、ストリームが再び準備完了になるまでに非常に長い遅延があるようです。なぜ私のin.ready()は長時間かかるのですか?

これは、デバッグのための多くのテストの後で、これが問題の領域のコードであることを確かめています。サーバー側では

: サーバーが未満を取ります。クライアント側で

if(inputLine.equals("RP")){ //this is the main update 
      timetoupdate = System.currentTimeMillis(); //start timer 
       ArrayList<Player> currentplayers =world.getPlayers(); //get the list of players 
       out.println(currentplayers.size()); //send the size 
       for(int pl = 0; pl<currentplayers.size();pl++){ //loop through 
        Player player = currentplayers.get(pl); //get the player object 
        out.println(""+pl); 
        out.println(player.getUsername()); 
        out.println(player.getType()); 
        out.println(player.getXloc()); 
        out.println(player.getYloc()); 
        out.println(player.getXvel()); 
        out.println(player.getYvel()); 
        out.println(player.getPressing()); 
        out.println(player.getLookingxloc()); 
        out.println(player.getLookingyloc()); 
        out.println(player.getTeam()); 
        out.flush(); 
        /* 
        id 
        username 
        class(type) 
        xloc 
        yloc 
        lxloc 
        lyloc 
        */ 
        // Just gaveout all info on player.getUsername() 
       } 

       System.out.println("Time this ("+inputLine+") part takes:"+(System.currentTimeMillis()-timetoupdate)); //stop timer 

out.println("RP"); //tell the server we are generally updating 

    String playercountstring = in.readLine(); //get the array size 
    int playercount = Integer.valueOf(playercountstring); //convert to int 

    for (int i = 0; i < playercount; i++) {//loop through all players 

     long timetoupdate = System.currentTimeMillis(); //start timer 
     while(!in.ready()){}//wait for input to become ready 
     System.out.println("time this (to ready) part takes:"+(System.currentTimeMillis()-timetoupdate));//stop timer 


     String toprocess = in.readLine(); //get id of player 
... and continues to get all info on this player 

私は、問題のある領域が完了するまでどのくらいのタイミング午前に気づくでしょうとして1ミリ秒ですが、クライアントの1つの領域が200ミリ秒かかる、特に前の行が配列のサイズを集めるのは1ミリ秒もかかりません。私は本当に問題が何であるかについてここで迷っています。私は必ずしも解決策が必要なわけではありません。ありがとう!

+0

出力をフラッシングしていて、ソケットにTCP_NODELAYを設定していますか? – zapl

+0

サーバーコードのように、出力をフラッシュします。ソケットは確かにTCP_NODELAYに設定されています – thetrueprime

+0

両側にはアウトバウンドTCPバッファがあるので、どこにでも設定する必要があります。あなたが見ている200msの間、 "RP"をバッファリングしているクライアントもいるかもしれません。 – zapl

答えて

0

しばしばトラブル原因TCPコネクションで2ポイントがあります。それはシステムに引き渡される前にデータを収集するJava内

  • バッファ、例えばは、データを送信する必要がいったんBufferedOutputStream
    • 以内に、あなたは、システムのアウトバウンドTCPバッファ
      • flush()
    • を呼び出す必要が通常のソリューションは、Nagle's Algorithmことを無効にTCP_NODELAYオプションを設定することですそうでなければパケットの送信を遅らせることができる。 other waysもあります。

これらの場所は、接続の両側両側に存在します。

少し例:

class Server { 
    public void serve(int port) throws IOException { 
     try (ServerSocket serverSocket = new ServerSocket(port)) { 
      for(;;) { 
       Socket clientSocket = serverSocket.accept(); 
       clientSocket.setTcpNoDelay(true); 
       Thread clientThread = new Thread(() -> handleClient(clientSocket)); 
       clientThread.start(); 
      } 
     } 
    } 

    private void handleClient(Socket clientSocket) { 
     try (
      Socket socket = clientSocket; // tricks try-with-resource into handling the socket 
      OutputStream out = socket.getOutputStream(); 
      InputStream in = socket.getInputStream(); 
      BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8)); 
      BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)) 
      ) { 

      while (true) { 
       String command = reader.readLine(); 
       switch (command) { 
        case "quit": 
         Util.send(writer, "ok"); 
         return; // ends this thread. 
        case "time": 
         Util.send(writer, String.valueOf(System.currentTimeMillis())); 
         break; 
       } 
      } 

     } catch (IOException e) { 
      System.out.println("Client connection closed due to " + e); 
      // maybe do something 
     } 
    } 
} 

とクライアントの両側がsocket.setTcpNoDelay(true)と呼ばれているか

class Client { 
    public void connect(String host, int port) throws UnknownHostException, IOException { 
     try (
      Socket socket = new Socket(host, port); 
      OutputStream out = socket.getOutputStream(); 
      InputStream in = socket.getInputStream(); 
      BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8)); 
      BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)) 
      ) { 

      socket.setTcpNoDelay(true); 

      Util.send(writer, "time"); 
      String time = reader.readLine(); 
      System.out.println("Server time: " + time); 
      Util.send(writer, "quit"); 
      System.out.println(reader.readLine()); 
      return; 
     } 
    } 
} 

注意。 最後に、行を書き込むコードとflush()を呼び出して、データがアプリケーションレベルのバッファに滞留していないことを確認します。

関連する問題