在java中,将字节数组写入socket outputstream的最快方法是什么

在java中,将字节数组写入socket outputstream的最快方法是什么,java,sockets,outputstream,Java,Sockets,Outputstream,作为标题,并假设字节数组的大小不大于16 KB 目前我正在为MySQL实现一个中间件(比如MySQL代理),它需要高吞吐量。但是从套接字读取数据和将数据写入套接字所导致的开销。现在,我使用 in = new DataInputStream(new BufferedInputStream(socket.getInputStream())) 及 在读写数据时,我使用 in.read(byte[]b)和out.write(byte[]b,int offset,int len)与out.flush()

作为标题,并假设字节数组的大小不大于16 KB

目前我正在为MySQL实现一个中间件(比如MySQL代理),它需要高吞吐量。但是从套接字读取数据和将数据写入套接字所导致的开销。现在,我使用

in = new DataInputStream(new BufferedInputStream(socket.getInputStream()))

在读写数据时,我使用

in.read(byte[]b)
out.write(byte[]b,int offset,int len)
out.flush()


有谁能告诉我更好的方法吗?

因为您只是转发字节,所以不使用DataInputStream,而只使用BufferedInputStream.read()和BufferedOutputStream.write(),可以节省一点时间。

为了获得最佳吞吐量,您需要使用NIO和ByteBuffers。NIO将大部分工作保持在本机代码中读写套接字,因此可以更快

编写好的NIO代码要复杂得多,但这取决于您所追求的性能,值得付出努力


这里有一些很好的NIO示例,还有一些很好的介绍和比较。我使用过的一个资源是。

如果您正在编写字节数组,那么它没有多大区别。网络是限制因素,而不是API。我认为你已经接近最佳状态了。最重要的因素是内核中套接字发送缓冲区的大小,以及接收器中套接字接收缓冲区的大小


您可以研究NIO和直接缓冲区,但我怀疑您是否会看到显著的差异。直接缓冲区实际上适用于在通道之间进行复制的情况,而NIO的其余部分实际上是关于可伸缩性而不是单个通道上的性能。

正如EJP提到的,网络是限制因素。但这并没有阻止我尝试在不使用NIO的情况下实现最快的实现。问题是,您可以在向另一个/套接字写入数据时从套接字读取数据。一个线程无法执行此操作(读或写),因此需要多个线程。但如果没有NIO,则需要大量线程(不过大部分线程都处于空闲状态,等待I/O)。NIO稍微复杂一点,但是当有大量低容量的连接时,它非常擅长使用很少的线程(参见Baldy提到的文章的摘要)

无论如何,下面是一个非NIO测试类,您可以对其进行更新并使用它来亲自查看什么是(不是)限制因素

public class SocketForwarder {

public static void main(String[] args) {

    try {
        new SocketForwarder().forward();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public static final int portNumber = 54321;
public static final int maxSend = 1024 * 1024 * 100; // 100 MB
public static final int bufSize = 16 * 1024;
public static final int maxBufInMem = 128;

private static final SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss.SSS");

private final ExecutorService tp = Executors.newCachedThreadPool();
private final ArrayBlockingQueue<byte[]> bq = new ArrayBlockingQueue<byte[]>(maxBufInMem); 
private final CountDownLatch allReceived = new CountDownLatch(1);
private Socket from, to, sender, receiver;
private int bytesSend, bytesReceived;

public void forward() throws Exception {

    tp.execute(new Runnable() {
        public void run() {
            ServerSocket ss = null;
            try {
                ss = new ServerSocket(portNumber);
                from = ss.accept();
                to = ss.accept();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try { ss.close(); } catch (Exception ignored) {}
            }
        }
    });

    sender = new Socket(InetAddress.getLocalHost(), portNumber);
    receiver = new Socket(InetAddress.getLocalHost(), portNumber);

    // Setup proxy reader.
    tp.execute(new Runnable() {
        public void run() {
            byte[] buf = new byte[bufSize];
            try {
                InputStream in = from.getInputStream();
                int l = 0;
                while ((l = in.read(buf)) > 0) {
                    byte[] bufq = new byte[l];
                    System.arraycopy(buf, 0, bufq, 0, l);
                    bq.put(bufq);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
    // Setup proxy writer.
    tp.execute(new Runnable() {
        public void run() {
            try {
                OutputStream out = to.getOutputStream();
                while (true) {
                    byte[] bufq = bq.take();
                    out.write(bufq);
                    out.flush();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
    // Start receiver.
    tp.execute(new Runnable() {
        public void run() {
            byte[] buf = new byte[bufSize];
            try {
                InputStream in = receiver.getInputStream();
                int l = 0;
                while (bytesReceived < maxSend && (l = in.read(buf)) > 0) {
                    bytesReceived += l;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(df.format(new Date()) + " bytes received: " + bytesReceived);
            allReceived.countDown();
        }
    });
    // Start sender.
    tp.execute(new Runnable() {
        public void run() {
            Random random = new Random();
            try {
                OutputStream out = sender.getOutputStream();
                System.out.println(df.format(new Date())  + " start sending.");
                while (bytesSend < maxSend) {
                    byte[] buf = new byte[random.nextInt(bufSize)];
                    out.write(buf);
                    out.flush();
                    bytesSend += buf.length;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("Bytes send: " + bytesSend);
        }
    });
    try { 
        allReceived.await();
    } finally {
        close(sender);
        close(from);
        close(to);
        close(receiver);
        tp.shutdownNow();
    }
}

private static void close(Socket s) {
    try { s.close(); } catch (Exception ignored) {} 
}

}
公共类SocketForwarder{
公共静态void main(字符串[]args){
试一试{
新的SocketForwarder().forward();
}捕获(例外e){
e、 printStackTrace();
}
}
公共静态最终int端口号=54321;
公共静态final int maxSend=1024*1024*100;//100 MB
公共静态最终int bufSize=16*1024;
公共静态最终int maxBufInMem=128;
私有静态最终SimpleDataFormat df=新SimpleDataFormat(“HH:mm:ss.SSS”);
私有最终执行器服务tp=Executors.newCachedThreadPool();
私有最终ArrayBlockingQueue bq=新的ArrayBlockingQueue(maxBufInMem);
私有最终CountDownLatch allReceived=新的CountDownLatch(1);
来自、到、发送方、接收方的专用套接字;
私有int bytesSend,bytesserved;
public void forward()引发异常{
tp.execute(新的Runnable(){
公开募捐{
ServerSocket ss=null;
试一试{
ss=新服务器套接字(端口号);
from=ss.accept();
to=ss.accept();
}捕获(例外e){
e、 printStackTrace();
}最后{
请尝试{ss.close();}捕获(忽略异常){}
}
}
});
sender=新套接字(InetAddress.getLocalHost(),端口号);
receiver=新套接字(InetAddress.getLocalHost(),端口号);
//安装代理读取器。
tp.execute(新的Runnable(){
公开募捐{
字节[]buf=新字节[bufSize];
试一试{
InputStream in=from.getInputStream();
int l=0;
而((l=in.read(buf))>0){
字节[]bufq=新字节[l];
系统阵列副本(buf,0,bufq,0,l);
bq.put(bufq);
}
}捕获(例外e){
e、 printStackTrace();
}
}
});
//安装代理编写器。
tp.execute(新的Runnable(){
公开募捐{
试一试{
OutputStream out=to.getOutputStream();
while(true){
字节[]bufq=bq.take();
输出。写入(bufq);
out.flush();
}
}捕获(例外e){
e、 printStackTrace();
}
}
});
//启动接收器。
tp.execute(新的Runnable(){
公开募捐{
字节[]buf=新字节[bufSize];
试一试{
InputStream in=receiver.getInputStream();
int l=0;
而(bytesReceived0){
字节数+=l;
}
}捕获(例外e){
e、 printStackTrace();
}
System.out.println(df.format(new Date())+“接收字节数:”+接收字节数);
全部接收。倒计时();
}
});
//启动发送器。
tp.execute(新的Runnable(){
公开募捐{
随机=新随机();
试一试{
OutputStream out=sender.getOutputStream();
System.out.println(df.format(new Date())+“开始发送”);
while(bytesSendpublic class SocketForwarder {

public static void main(String[] args) {

    try {
        new SocketForwarder().forward();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public static final int portNumber = 54321;
public static final int maxSend = 1024 * 1024 * 100; // 100 MB
public static final int bufSize = 16 * 1024;
public static final int maxBufInMem = 128;

private static final SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss.SSS");

private final ExecutorService tp = Executors.newCachedThreadPool();
private final ArrayBlockingQueue<byte[]> bq = new ArrayBlockingQueue<byte[]>(maxBufInMem); 
private final CountDownLatch allReceived = new CountDownLatch(1);
private Socket from, to, sender, receiver;
private int bytesSend, bytesReceived;

public void forward() throws Exception {

    tp.execute(new Runnable() {
        public void run() {
            ServerSocket ss = null;
            try {
                ss = new ServerSocket(portNumber);
                from = ss.accept();
                to = ss.accept();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try { ss.close(); } catch (Exception ignored) {}
            }
        }
    });

    sender = new Socket(InetAddress.getLocalHost(), portNumber);
    receiver = new Socket(InetAddress.getLocalHost(), portNumber);

    // Setup proxy reader.
    tp.execute(new Runnable() {
        public void run() {
            byte[] buf = new byte[bufSize];
            try {
                InputStream in = from.getInputStream();
                int l = 0;
                while ((l = in.read(buf)) > 0) {
                    byte[] bufq = new byte[l];
                    System.arraycopy(buf, 0, bufq, 0, l);
                    bq.put(bufq);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
    // Setup proxy writer.
    tp.execute(new Runnable() {
        public void run() {
            try {
                OutputStream out = to.getOutputStream();
                while (true) {
                    byte[] bufq = bq.take();
                    out.write(bufq);
                    out.flush();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
    // Start receiver.
    tp.execute(new Runnable() {
        public void run() {
            byte[] buf = new byte[bufSize];
            try {
                InputStream in = receiver.getInputStream();
                int l = 0;
                while (bytesReceived < maxSend && (l = in.read(buf)) > 0) {
                    bytesReceived += l;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(df.format(new Date()) + " bytes received: " + bytesReceived);
            allReceived.countDown();
        }
    });
    // Start sender.
    tp.execute(new Runnable() {
        public void run() {
            Random random = new Random();
            try {
                OutputStream out = sender.getOutputStream();
                System.out.println(df.format(new Date())  + " start sending.");
                while (bytesSend < maxSend) {
                    byte[] buf = new byte[random.nextInt(bufSize)];
                    out.write(buf);
                    out.flush();
                    bytesSend += buf.length;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("Bytes send: " + bytesSend);
        }
    });
    try { 
        allReceived.await();
    } finally {
        close(sender);
        close(from);
        close(to);
        close(receiver);
        tp.shutdownNow();
    }
}

private static void close(Socket s) {
    try { s.close(); } catch (Exception ignored) {} 
}

}