加快我的Java tcp传输!

时间:2009-07-27 04:08:42

标签: java networking tcp sockets performance

我需要加快千兆以太网连接的传输速度。现在,我正在做一些几乎完全像这样的事情,但是当我在下面运行这段代码时,我只看到了大约40%。

我还在测试之前在我的所有(Mac Pro)计算机上运行了此脚本

#!/bin/bash

sudo sysctl -w net.inet.tcp.win_scale_factor=8
sudo sysctl -w kern.ipc.maxsockbuf=16777216
sudo sysctl -w net.inet.tcp.sendspace=8388608
sudo sysctl -w net.inet.tcp.recvspace=8388608

实际代码如下:

import java.io.*;
import java.nio.*;
import java.net.*;

public class BandwidthTester {
private static final int OUT_BUF = (1 << 17),
                    IN_BUF = (1 << 17), SEND_BUF = (1 << 22), RECV_BUF = (1 << 22);
public static void main(String[] args) {
    try {
        // server
        if (args.length == 0) {
            ServerSocket sock = new ServerSocket();
            sock.bind(new InetSocketAddress(41887));

            // wait for connection
            Socket s = sock.accept();

            s.setSendBufferSize(SEND_BUF);

            System.out.println("Buffers: " + s.getSendBufferSize() + " and " + s.getReceiveBufferSize());

            sock.close();

            BufferedOutputStream bOut = new BufferedOutputStream(s.getOutputStream(), OUT_BUF);

            // send lots of data
            sendLotsOfData(bOut);
        } else if (args.length == 2) {
            String host = args[0];
            int port = Integer.parseInt(args[1]);

            System.out.println("Connecting to " + args[0] + ":" + args[1]);

            Socket sock = new Socket();
            sock.setReceiveBufferSize(RECV_BUF);
            sock.connect(new InetSocketAddress(host, port));

            System.out.println("Buffers: " + sock.getSendBufferSize() + " and " + sock.getReceiveBufferSize());

            BufferedInputStream bIn = new BufferedInputStream(sock.getInputStream(), IN_BUF);
            getLotsOfData(bIn);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}


public static void getLotsOfData(InputStream in) {
    System.out.println("Getting data...");
    try {
        long start = System.currentTimeMillis();

        ByteBuffer intConv = ByteBuffer.allocate(4);

        in.read(intConv.array());
        int len = intConv.getInt(0);
        for (int i=0; i < len; i++) {
            in.read(intConv.array());
            int val = intConv.getInt(0);
        }

        long end = System.currentTimeMillis();

        double elapsed = ((double)(end - start)) / (1000.0);

        System.out.println("Read in " + elapsed + " seconds: " + ( (4.0*8.0*len/elapsed) + " bits per second"));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public static void sendLotsOfData(OutputStream out) {
    System.out.println("Sending data...");
    try {
        long start = System.currentTimeMillis();

        int len = (1 << 29);

        ByteBuffer intConv = ByteBuffer.allocate(4);
        intConv.putInt(0, len);
        out.write(intConv.array());
        for (int i=0; i < len; i++) {
            intConv.putInt(0, i);
            out.write(intConv.array());
        }

        out.flush();

        long end = System.currentTimeMillis();

        double elapsed = ((double)(end - start)) / (1000.0);

        System.out.println("Sent in " + elapsed + " seconds: " + ( (4.0*8.0*len/elapsed) + " bits per second"));
    }
    catch (Exception e) {
        e.printStackTrace();
    }
}
}

有什么建议吗?发送所有这些数据大约需要42秒,但即使是10%的改进也会对我的程序产生巨大影响。

1 个答案:

答案 0 :(得分:1)

您可能尝试的一件事是为ByteBuffer使用更大的缓冲区。从4个字节到16个,我从12秒的传输时间到9秒的传输时间。 (使用2 ^ 26而不是2 ^ 29测试长度)

那就是说,它是在当地运行的;所以不应该遇到实际的网络问题。

发送的修改代码有点脏:

ByteBuffer intConv = ByteBuffer.allocate(16);
intConv.putInt(0, len);
out.write(intConv.array(),0,4);
for (int i=0; i < len; i+=4) {
    for(int j=0; j<4; j++)
        intConv.putInt(4*j, i);
    out.write(intConv.array());
}

接收:

ByteBuffer intConv = ByteBuffer.allocate(16);
in.read(intConv.array(),0,4);
int len = intConv.getInt(0);
for (int i=0; i < len; i+=4) {
    in.read(intConv.array());
    for(int j=0; j<4; j++)
    {
      int val=intConv.getInt(j*4);
    }
}

显然,接收端需要进行一些修改来处理奇怪和奇怪的情况,例如“如果只剩下3个整数/从流中读取的内容”,但我认为这足以看出它是否能提高性能。