низкая производительность сокета Java на локальном хосте - PullRequest
0 голосов
/ 06 декабря 2018

Я создаю простое сетевое приложение Java, и у меня проблема с производительностью.
Приложение очень простое и состоит из 2 частей ( исходный код ):

  • Сервер, который является основным потоком.
  • Клиент, который является новым потоком, который был запущен основным.

Я пытаюсь отправить много небольших данных, но максимальная скорость отправкисоставляет 50 пакетов в секунду.
Так что в моем поиске я нашел этот вопрос с той же самой проблемой.
Когда я добавил поток Buffered в выходной поток, скорость становится больше (тысячв секунду)
В wireshark я очень хорошо вижу разницу:

  • При медленном запуске есть push-флаг и в другом пакете ack-флаг, а некоторые ack могут достигать даже 45 миллисекундзадержка, и использование процессора было очень низким.
  • В быстром запуске весь пакет содержит push и ack вместе, и при этом задержка составляет не более 1 миллисекунды, а загрузка процессора была высокой.

Iнашел также этот связанный вопрос , который не помогает.

Почему эта простая строка кода так отличается?
И почему простое решение в java такое медленное?

1 Ответ

0 голосов
/ 06 декабря 2018

Сокеты исторически открываются с использованием включенного алгоритма Нейгла , который задерживает небольшие пакеты в попытке оптимизировать сетевое взаимодействие.

При работе с небольшими пакетами следует установить сокет TCP_NODELAYвариант.В Java вы можете сделать это, позвонив socket.setTcpNoDelay(true);

После настройки я получаю:

  • 12000 пакетов / с без буфера
  • 26000 пакетов /s с буфером

Мой скорректированный код:

public class Test {
    static DataOutputStream cout(Socket s) throws IOException {
        return new DataOutputStream( (s.getOutputStream()));
//        return new DataOutputStream(new BufferedOutputStream(s.getOutputStream()));
    }
    static DataInputStream cin(Socket s) throws IOException {
        return new DataInputStream( (s.getInputStream()));
    }
    public static void main(String[] args) throws IOException, InterruptedException {
        ServerSocket server = new ServerSocket(12345);
        new Thread(() -> {
            try {
                Thread.sleep(1000);
                Socket client = new Socket("127.0.0.1", 12345);
                client.setTcpNoDelay(true);
                DataOutputStream out = cout(client);
                DataInputStream in = cin(client);
                long tm1 = System.currentTimeMillis();
                int lastCount = 0;
                for (int i=0;i<300000;i++) {
                    int a = in.readInt();
                    out.writeInt(a);
                    out.flush();
                    long tm2 = System.currentTimeMillis();
                    if ((tm2 - tm1) >= 1000) {
                        System.out.println(i - lastCount);
                        lastCount = i;
                        tm1 += 1000;
                    }
                }
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        Socket client=server.accept();
        client.setTcpNoDelay(true);
        DataOutputStream out = cout(client);
        DataInputStream in = cin(client);
        for (int i=0;i<300000;i++){
            out.writeInt(i);
            out.flush();
            if (i!=in.readInt()){
                System.out.println("ERROR");
            }
        }
        client.close();
        server.close();
        Thread.sleep(1000);
    }
}
...