Огромная задержка при подключении в Java

1

(ОБНОВЛЕННЫЙ КОД) Я пытаюсь заставить клиентов общаться с сервером (я сделал простые клиент-серверные приложения, например, в чате). Связь создана, но есть огромная задержка (я отправляю координаты от клиента к серверу). Это более 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 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 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();
    }
}

Что вызывает задержку? Я искал причину часами, но безуспешно.

Теги:
multithreading
sockets
delay

3 ответа

2

Скорее всего, вам нужно вызвать flush() на стороне клиента. Даже если это не ваша текущая проблема, это, вероятно, хорошая идея.

Потоки могут буферизовать их содержимое, то есть они не могут отправлять данные в пункт назначения (будь то диск или по проводке на сервер) в тот момент, когда вы вызываете write (или writeInt в этом случае). Вместо этого они могут подождать, пока они не получат достаточное количество данных, чтобы сделать перевод "стоящим". Если бы они не вели себя таким образом, они в конечном итоге делали много неэффективных, меньших передач. Недостатком всего этого является то, что вам может потребоваться сбросить flush чтобы сообщить потоку, что вы сделали передачу данных некоторое время, и что поток должен идти вперед и инициировать передачу.

  • 0
    Почему? И почему только на стороне клиента?
  • 0
    Вы должны вызвать флеш с обеих сторон, но вы видите задержку на клиенте ...
Показать ещё 5 комментариев
0

Имейте в ss.sendEveryone(tmb) что ваш вызов ss.sendEveryone(tmb) синхронизируется на объекте ss. Я предполагаю, что это static переменная где-то, которая содержит ссылку на всех клиентов. Это означает, что если одновременно будет отправлено несколько клиентов, многие вызовы sendEveryone будут происходить сразу, и все они выйдут в очередь, ожидая завершения остальных, прежде чем эти потоки смогут вернуться и прочитать больше данных от клиента снова.

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

  • 0
    Это происходит только с 2 клиентами и сервером. Если я удалю синхронизированный, отправленные данные будут испорчены.
  • 0
    Хорошо, это хорошая информация, чтобы знать. Я определенно не защищал удаление синхронизированных вообще, хотя это, возможно, не должно быть настолько жестким, как это ...
Показать ещё 2 комментария
0

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

например, в Port Scanners, вы должны использовать много потоков для ускорения поиска...

  • 0
    Каждый сокет имеет свой собственный поток, это только часть моего кода.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню