【问题标题】:Can someone help me speed up my netcode in Java?有人可以帮助我加快我在 Java 中的网络代码吗?
【发布时间】:2009-12-18 01:46:27
【问题描述】:

好的,所以我正在开发一款游戏(甚至还不是 Alpha 版),它应该是一个 1 对 1 的格斗游戏,其中一个人托管服务器,另一个人连接。但是现在代码太迟钝了,无法做任何事情。有人可以看看它并告诉我如何加快速度吗? PS:我也在使用 Slick2D 库。

服务器:

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

【问题讨论】:

  • 或许您应该 (a) 分析应用程序并告诉我们慢的部分是什么,或者 (b) 询问如何分析应用程序

标签: java client client-server


【解决方案1】:

是否只有当客户端位于服务器的远程计算机上时才会出现延迟?如果是这样并且你在两个盒子之间有一个很好的 ping 时间,那么我会大胆猜测并说你可能在这里遇到了 Nagle 的算法?您推送的数据非常小(writeInt)。

您可以尝试使用 BufferedOutputStream 中介,但如果您想尝试快速修复,您也可以尝试在您的套接字上禁用 Nagle。

Socket.setTcpNoDelay(true);

【讨论】:

  • 如果我将套接字连接到“localhost”没问题,但如果我将它设置为我的 IP,它就会变得迟钝。设置没有延迟有点帮助。
【解决方案2】:

好吧,您提供的代码不完整...我打算这样做,然后引导您完成操作,以便确定您会看到什么...但是我们将使用我们现有的。

1) 在同一台机器上为客户端和服务器运行它——它仍然很慢吗? 2)机器之间Ping,看看速度如何 3) 分析应用程序。

#1 有助于查看是否是网络问题。同一台机器上的客户端和服务器都消除了网络。

#2 有助于查看是否是网络问题。如果 ping 不好,那么游戏会很慢。

#3 更难做到,但会告诉你代码中哪里慢。

要分析一下Visual VM(或者如果您使用的是netbeans,只需在其中分析它...... eclipse 可能也有一些东西,也许是一个插件)。

对于分析,我将从服务器开始,看看那里的速度慢,然后转到客户端。我建议这样做只是因为服务器中发生的事情较少,所以应该更容易看到发生了什么。

【讨论】:

    【解决方案3】:

    嗯,有几件事你可以马上尝试,但你需要做一些工作才能做你想做的事。

    首先,您的客户端和服务器都处于非常紧密的循环中。通常,像您正在使用的循环应该在每次通过时休眠最少的时间,以防止循环消耗过多的 CPU 无所事事。

    其次,您可能应该使用非阻塞 I/O(在尝试读取之前检查来自每个客户端的输入)。

    最后,除非您想进行有关 Java 网络的学习练习,或者除非您有需要非标准通信协议的特定目标,否则您可能需要考虑使用可以简单扩展的服务器框架。一个简单的方法是使用 Jetty 或 Tomcat 构建您的服务器端,并为您的客户端使用 Apache HTTPClient。

    如果您选择使用专用服务器,Core Java 书籍或 Java Networking (O'Reilly) 书籍中的简单服务器框架将为您提供更好的基础。

    希望对您有所帮助。

    【讨论】:

      【解决方案4】:

      您是否尝试过使用ObjectOutputStreamObjectInputStream 以外的其他方式发送和接收数据?使用这些涉及序列化和反序列化对象,而且似乎(尽管只是预感)使用DataOutputStream 可能会更快。

      【讨论】:

      【解决方案5】:

      这取决于它为什么慢。这里有几个建议

      1. 仅使用非阻塞 I/O。作为此规则的特例,切勿使用 RPC。
      2. 考虑在适当的情况下进行客户端预测。客户端预测是假设客户端想要做的事情是可以的,并在客户端上绘制就好像它是可以的。大多数(如果不是全部)网络游戏都使用此功能。
      3. 接受您在实时游戏中的玩家之间没有“同步”状态。它只是不会发生。

      另外,请定义“变得迟钝”的含义。你的意思是代码给出的帧率很差吗?移动注册需要很长时间?弄清楚这一点将是优化的第一步。

      祝你好运。让格斗游戏在网络上响应将是一项艰巨的任务,即使对于具有网络游戏编程经验的专业开发人员也是如此。您可能需要在一定程度上修改您的游戏设计以帮助隐藏延迟 - 某些事情通过网络是不可能的。

      【讨论】:

        【解决方案6】:

        如果您愿意,可以尝试使用数据报套接字。如果底层数据包被丢弃,它就会消失,但由于您只是在更新位置,它应该没问题。

        【讨论】:

          猜你喜欢
          • 2017-12-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-03-08
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多