简体   繁体   English

本地主机上的Java套接字性能变慢

[英]slow java socket performance on localhost

I am building a simple java network app and I have a performance issue. 我正在构建一个简单的Java网络应用程序,但是我遇到了性能问题。
The app is very simple and contains 2 parts ( source code ): 该应用程序非常简单,包含2个部分( 源代码 ):

  • The server which is the main thread. 服务器是主线程。
  • The client which is new thread that has started by main. 客户端是由main启动的新线程。

I am trying to send a lot of small data but the maximum send rate is 50 package per second. 我正在尝试发送大量小数据,但最大发送速率为每秒50个包裹。
So In my search I have found this question with the very same problem. 因此,在我的搜索中,我发现了这个问题 ,并且存在相同的问题。
When I added the Buffered stream to the output stream, the rate goes bigger (thousand per second) 当我将Buffered流添加到输出流时,速率变大(每秒千)
In wireshark I can see the difference very nicely: 在wireshark中,我可以很好地看到区别:

  • In the slow run there is push flag and in different package the ack flag, and some ack can reach even 45 millisecond of delay, and the cpu use was very low. 在慢速运行中,有推标志,在不同的程序包中有ack标志,有些ack甚至可以达到45毫秒的延迟,并且CPU使用率非常低。
  • In the fast run all the package contains push and ack together and for all of then the delay is no more then 1 millisecond, and the cpu use was high. 在快速运行中,所有程序包都将推和确认放在一起,因此所有延迟都不超过1毫秒,并且CPU使用率很高。

I found also this related question that does not help. 我也发现这个相关问题没有帮助。

Why is that simple line of code make so different? 为什么那简单的代码行如此不同?
And why the simple solution in java so slow? 以及为什么简单的Java解决方案这么慢?

Sockets are historically opened using the Nagle's algorithm enabled, which delays small packets in an attempt to optimize network communication. 历史上,套接字是使用启用的Nagle算法打开的,该算法会延迟小数据包,以优化网络通信。

When working with small packets you should set the TCP_NODELAY socket option. 处理小数据包时,应设置TCP_NODELAY套接字选项。 In Java you can do it by calling socket.setTcpNoDelay(true); 在Java中,您可以通过调用socket.setTcpNoDelay(true);

After the adjustment I'm getting: 调整后,我得到:

  • 12000 packets/s without a buffer 12000包/秒,无缓冲区
  • 26000 packets/s with a buffer 带缓冲区26000个数据包/秒

My adjusted code: 我调整后的代码:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM