java - java中socket时出现巨大延迟

标签 java multithreading sockets delay

(更新的代码) 我试图让客户端与服务器进行通信(我制作了简单的客户端服务器应用程序,例如聊天室)。通信已创建,但存在巨大的延迟(我将坐标从客户端发送到服务器)。超过10秒(有时甚至更长)。可能是什么问题呢? 客户:

    public class GameComponent extends Canvas implements Runnable {
    private static final long serialVersionUID = 1L;

    private static final int WIDTH = 320;
    private static final int HEIGHT = 240;
    private static final int SCALE = 2;

    private boolean running;

    private JFrame frame;
    Thread thread;

    public static final int GRID_W = 16;
    public static final int GRID_H = 16;

    private Socket socket;
    private DataInputStream reader;
    private DataOutputStream writer;

    private HashMap<Integer, OtherPlayer> oPlayers;
    private ArrayList<OtherPlayer> opList;
    private int maxID = 1;

    private int ID;

    Player player;

    public GameComponent() {
        //GUI code..

        oPlayers = new HashMap<Integer, OtherPlayer>();  //Hash map to be able to get players by their ID's
        opList = new ArrayList<OtherPlayer>();  //And an array list for easier drawing

        setUpNetworking();

        start();
    }

    public void start() {
        if (running)
            return;
        running = true;
        thread = new Thread(this);
        player = new Player(GRID_W * 2, GRID_H * 2);
        thread.start();
    }

    public void stop() {
        if (!running)
            return;
        running = false;
    }

    public void run() {  //The main loop, ticks 60 times every second
        long lastTime = System.nanoTime();
        double nsPerTick = 1000000000D / 60D;

        int frames = 0;
        int ticks = 0;

        long lastTimer = System.currentTimeMillis();
        double delta = 0;

        while (running) {
            long now = System.nanoTime();
            delta += (now - lastTime) / nsPerTick;
            lastTime = now;

            boolean shouldRender = true;

            while (delta >= 1) {
                ticks++;
                tick(delta);
                delta -= 1;
                shouldRender = true;
            }

            try {
                Thread.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if (shouldRender) {
                frames++;
                render();
            }

            if (System.currentTimeMillis() - lastTimer >= 1000) {
                lastTimer += 1000;
                frames = 0;
                ticks = 0;
            }
        }
    }

    private void tick(double delta) {  //main logic
        player.move();
        try {
            writer.writeInt(ID);     //I send the player data here (id, x, y)
            writer.writeInt(player.getX());
            writer.writeInt(player.getY());
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private void render(Graphics2D g2d) {
        //rendering the stuff

        for (OtherPlayer i : opList) {  //drawing a black rectangle for every other player
            g2d.fillRect(i.getX(), i.getY(), GRID_W, GRID_H);
        }
    }

    private void render() {
        //more rendering...
    }

    public static void main(String[] args) {
        new GameComponent();
    }

    class TKeyListener implements KeyListener {
        //movement methods...
    }

    private void setUpNetworking() {  //This is where I make my message reader and data IO
        try {
            socket = new Socket("127.0.0.1", 5099);
            reader = new DataInputStream(socket.getInputStream());
            writer = new DataOutputStream(socket.getOutputStream());
            Thread rT = new Thread(new msgReader());
            rT.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    class msgReader implements Runnable {  //where I read messages
        public void run() {
            try {
                ID = reader.readInt();   //when I connect, I get an id from the server

                while(true) {   //my main loop
                    int oid = reader.readInt();   //get the read data id
                    int ox, oy;

                    ox = reader.readInt();   //get the read player's x and y
                    oy = reader.readInt();

                    if (oid != ID){   //If not reading myself
                        if (oPlayers.containsKey(oid)) {   //If a player with this id exists
                            OtherPlayer op = (OtherPlayer) oPlayers.get(oid);
                            op.setX(ox);  //set it's x, y
                            op.setY(oy);
                        } else {  //if it doesn't exist, create him
                            OtherPlayer op = new OtherPlayer(ox, oy);
                            opList.add(op);
                            oPlayers.put(oid, op);
                        }
                    }
                    maxID = reader.readInt();  //Allways read the highest current id from server
                }
            } catch(Exception ex) {
                ex.printStackTrace();
            }
        }
    }
}

服务器:

public class ServerBase {
    ServerSocket serverSocket;
    ArrayList<DataOutputStream> clients;
    private int id = 1;
    SyncSend ss = new SyncSend();

    class ClientHandler implements Runnable {
        private Socket soc;
        private DataInputStream reader;
        private int x;
        private int y;
        private int id;
        private boolean run = true;

        public ClientHandler(Socket s) {
            soc = s;
            try {
                reader = new DataInputStream(soc.getInputStream());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public void run() {
            try {               
                while (run) {
                    id = reader.readInt();
                    x = reader.readInt();
                    y = reader.readInt();

                    if (id == 2)
                        System.out.println("x: " + x + " y: " + y);

                    int[] tmb = {id, x, y};
                    ss.sendEveryone(tmb);
                }
            } catch (Exception e) {
                run = false;
                clients.remove(this);
            }
        }
    }

    class SyncSend {
        public synchronized void sendEveryone(int[] a) throws SocketException {
            ArrayList<DataOutputStream> cl = (ArrayList<DataOutputStream>) clients.clone();
            Iterator<DataOutputStream> it = cl.iterator();
            while(it.hasNext()){
                try {
                    DataOutputStream writer = (DataOutputStream) it.next();
                    writer.writeInt(a[0]);
                    writer.writeInt(a[1]);
                    writer.writeInt(a[2]);
                    writer.writeInt(id-1);
                    writer.flush();
                } catch (Exception ex) {
                    throw new SocketException();
                }
            }
        }
    }


    public void init() {
        clients = new ArrayList<DataOutputStream>();

        try {
            serverSocket = new ServerSocket(5099);

            while(true) {
                Socket clientSocket = serverSocket.accept();
                DataOutputStream clientWriter = new DataOutputStream(clientSocket.getOutputStream());
                clients.add(clientWriter);
                clientWriter.writeInt(id);
                id++;

                Thread t = new Thread(new ClientHandler(clientSocket));
                t.start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new ServerBase().init();
    }
}

什么原因导致延迟?我已经寻找原因几个小时了,但没有成功。

最佳答案

您很可能需要调用flush()在客户端。即使这不是您当前的问题,这也可能是个好主意。

流可能会缓冲其内容,这意味着它们可能不会在您调用 write 时将数据发送到其目的地(无论是磁盘还是通过线路连接到服务器) (在本例中为 writeInt)。相反,他们可能会等到获得足够多的数据以使传输“值得”。如果他们不这样做,他们最终会进行大量低效、规模较小的转账。所有这一切的缺点是您可能需要调用 flush告诉流您已经完成发送数据一段时间,并且流应该继续并启动传输。

关于java - java中socket时出现巨大延迟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22516261/

相关文章:

java - Cassandra = 内存/编码- key 占用空间(哈希/字节[]=>十六进制=>UTF16=>字节[])

java - opencsv转义单引号和双引号

java - 如何正确关闭这些线程

c++ - 构建 Boost_1_55_0 的示例异步 TCP 日间服务器

node.js - Socket.io 替代方案

java - 如何删除java中第一个和最后一个出现的句子

Java UDP 数据报包 - 切片数据以适应缓冲区大小

c# - 如何在 Visual Studio 2008 中获取线程窗口?

python - 如何使用 ctypes 和线程为 C 回调函数分配内存

Java套接字: open connections from server to client