Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Медленный отклик 
V
    Опции темы
Рубильник
Дата 10.5.2018, 12:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 6.6.2016

Репутация: нет
Всего: нет



Есть простой сервер и клиент.
Клиент отправляет пакет из 10-20 байт в котором есть число, сервер прочитывает это число, прибавляет 1 и возвращает обратно. Как только клиент прочитывает возвращенное значение, он отсылает пакет серверу обратно.

Т.е. самописная система для тестирования отклика по сети. Использованы только базовые средства java.
После записи делается flush() в обязательном порядке.

Если тестить локально, то получается 1000 откликов занимает 50-60 мс. Если сервер и клиент на разных компах (но внутри одной сети), то 100 откликов занимает целых 33 секунды, т.е. один отклик занимает треть секунды.

В чем может быть дело? Пингование стандартными средствами показывает гораздо быстрый отклик.

Может ли в этом виноватой быть ОС Windows XP?
PM MAIL   Вверх
AntonSaburov
Дата 10.5.2018, 12:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Штурман
****


Профиль
Группа: Модератор
Сообщений: 5658
Регистрация: 2.7.2002
Где: Санкт-Петербург

Репутация: 51
Всего: 118



Я сталкивался с ситуацией, когда пакет может "зависать" на свичах, если он маленький. 
Попробуйте организовать многопоточный вариант - например потоков 50 и каждый делает, что описано. На сервере тоже многопоточный вариант. Может сдвинется. Хотя гарантий конечно же нет.
PM MAIL WWW ICQ   Вверх
Рубильник
Дата 10.5.2018, 13:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 6.6.2016

Репутация: нет
Всего: нет



Система строится по концепции тонкого клиента, где многие действия пользователя формирует обращение к серверу. Требовалось оценить скорость отклика, чтобы у пользователя не возникало дискомфорта.

Не очень понимаю, чем может помочь здесь много поточность? Меня же интересует именно отклик, а не пропускная способность.

В играх сигнал идет от клиента, обрабатывается на сервере и возвращается (для визуализации). Пусть реально это 20 fps, т.е. отклик всего 50 мс. И меня бы это устроило, но треть секунды - это очень много, и визуально очень заметно, это ещё без времени для отработки на самом сервере (кто знает какие там запросы).

Меня интересует "кто виноват?"

Если причина тому сама Java - это одно, значит придется менять концепцию. Если виновата ОС или сетевые настройки, то это совсем другое дело.

На всякий случай выкладываю код теста.
Код

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class ClientFrame extends JFrame{
    public JButton buttonStart = new JButton("Тест");
    public JLabel label = new JLabel("          ");
    public Socket socket = null;
    
    public void configurateGUI(){   
        setBounds(100, 100, 300, 200);
        setTitle("Клиентская сторона");
        JPanel mainPanel = new JPanel();
        mainPanel.add(buttonStart);
        mainPanel.add(label);
        getContentPane().add(mainPanel);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
        buttonStart.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                buttonStart.setEnabled(false);
                try {
                    socket = new Socket(ServerFrame.HOST_NAME, ServerFrame.HOST_PORT);
                    DataInputStream inputStream = new DataInputStream(socket.getInputStream());
                    DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
                    long timeStart = System.currentTimeMillis();
                    outputStream.writeUTF("Packet ");
                    outputStream.writeInt(0);
                    outputStream.flush();
                    while(true){
                        String s = inputStream.readUTF();
                        int value = inputStream.readInt();
                        if(value<1000){
                            outputStream.writeUTF(s);
                            outputStream.writeInt(value);
                            outputStream.flush();
                        }else{
                            break;
                        }
                    }
                    socket.close();
                    long timeFinish = System.currentTimeMillis();
                    label.setText("Ушло "+(timeFinish-timeStart));
                    buttonStart.setEnabled(true);
                } catch (IOException ex) {
                }
            }
        });
    }
    
    public static void main(String _a[]){
        ClientFrame frame = new ClientFrame();
        frame.configurateGUI();
        frame.setVisible(true);
    }
}


Код

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class ServerFrame extends JFrame{
    
    public static final String HOST_NAME="127.0.0.1";
    //public static final String HOST_NAME="192.168.0.17";
    public static final int HOST_PORT = 1049;
    
    public ServerSocket server = null;
    public boolean isRun = true;
    
    JButton buttonStart = new JButton("Старт");
    JButton buttonFinish = new JButton("Окончание");
    
    public void configurateGUI(){
        
        setBounds(100, 100, 300, 200);
        setTitle("Серверная сторона");
        buttonFinish.setEnabled(false);
        JPanel mainPanel = new JPanel();
        mainPanel.add(buttonStart);
        mainPanel.add(buttonFinish);
        getContentPane().add(mainPanel);
        setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        
        buttonStart.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                buttonFinish.setEnabled(true);
                try {
                    server = new ServerSocket(HOST_PORT);
                    Thread serverThread = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                while(isRun){
                                    Socket s = server.accept();
                                    SocketRunner runner = new SocketRunner(s, ServerFrame.this);
                                    Thread thread = new Thread(runner);
                                    thread.start();  
                                }
                            } catch (IOException ex) {
                            }
                        }
                    });
                    serverThread.start();
                } catch (IOException ex) {
                    System.out.println("Не удалось создать сервер");
                    System.exit(0);
                }
                buttonStart.setEnabled(false);
            }
        });
        buttonFinish.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                isRun = false;
                try {
                    server.close();
                } catch (IOException ex) {
                }
                System.exit(0);
            }
        });
    }
    
    public static void main(String _a[]){
        ServerFrame frame = new ServerFrame();
        frame.configurateGUI();
        frame.setVisible(true);
    }
}


Код


import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

public class SocketRunner implements Runnable{
    public Socket socket = null;
    public DataInputStream inputStream = null;
    public DataOutputStream outputStream = null;
    public ServerFrame frame = null;
            
    
    public SocketRunner(Socket _socket, ServerFrame _frame){
        frame = _frame;
        socket = _socket;
    }

    @Override
    public void run() {
        try {
            inputStream = new DataInputStream(socket.getInputStream());
            outputStream = new DataOutputStream(socket.getOutputStream());
            while(frame.isRun){
                String s = inputStream.readUTF();
                int value = inputStream.readInt();
                
                outputStream.writeUTF(s);
                outputStream.writeInt(value+10);
                outputStream.flush();
            }
        } catch (IOException ex) {
            try {
                socket.close();
            } catch (IOException ex1) {
            }
        }
    }
    
}


Это сообщение отредактировал(а) Рубильник - 10.5.2018, 13:13
PM MAIL   Вверх
AntonSaburov
Дата 10.5.2018, 14:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Штурман
****


Профиль
Группа: Модератор
Сообщений: 5658
Регистрация: 2.7.2002
Где: Санкт-Петербург

Репутация: 51
Всего: 118



Да просто маленькие пакеты могут тупо зависать на свичах. Т.к. вы их кидаете последовательно, то свич просто не прокидывает дальше. А вот если пакетов "накапливается" много, то есть вероятность, что они будут проброшены дальше. Т.к. Вы каждый раз отправляете маленький пакет и ждеме, то и получаете.
В случае многопоточности вы пробрасываете много пакетиков и их суммарный объем может позволить свичу их пробросить.

Но это я делаю только предположение. Не факт, что проблема здесь.
PM MAIL WWW ICQ   Вверх
Рубильник
Дата 10.5.2018, 15:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 6.6.2016

Репутация: нет
Всего: нет



Ради интереса поставил сниффер.

В логе задержка между приемом пакета от клиента и отправкой следующего составляет примерно 150 мс, и столько же примерно между отправкой клиента и получением нового. В сумме получается примерно 300 мс.

Получается, что виновата не сеть. Если бы был затык в сети (в оборудовании), то между приемом и отправкой была бы маленькая пауза, и большая между отправкой и приемом. Или я неправильно что-то понимаю?
PM MAIL   Вверх
AntonSaburov
Дата 10.5.2018, 16:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Штурман
****


Профиль
Группа: Модератор
Сообщений: 5658
Регистрация: 2.7.2002
Где: Санкт-Петербург

Репутация: 51
Всего: 118



Ну тогда надо профилировать - какой оператор "жрет много" и у кого. Самое простое - понатыкать везде логи.
PM MAIL WWW ICQ   Вверх
Рубильник
Дата 14.5.2018, 08:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 6.6.2016

Репутация: нет
Всего: нет



Разобрался. Всё дело в socket.setTcpNoDelay(true).

Delayed ACK нужно отключать и на сервере и на клиенте.
Теперь время отклика 0.5-1.5 мс. Что есть очень хорошо. 
PM MAIL   Вверх
AntonSaburov
Дата 14.5.2018, 13:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Штурман
****


Профиль
Группа: Модератор
Сообщений: 5658
Регистрация: 2.7.2002
Где: Санкт-Петербург

Репутация: 51
Всего: 118



Ну да - точно. Буферизуется пакет, если маленький. Как я и предполагал. Правда я не на тот девайс подумал smile
PM MAIL WWW ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1454 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.