测试环境

  • 两台RedHat6.5 64位虚拟机
  • JDK版本:1.7.0_21
  • 测试文件大小:212MB

NIO发送测试

1.服务端代码


public static void main(String[] args) { if(args.length != 1){ System.out.println("Usage : java -jar ServerTcpListener.jar port"); return; } try { final ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.socket().bind(new InetSocketAddress(Integer.parseInt(args[0]))); Thread th = new Thread(new Runnable() { @Override public void run() { try { serverSocketChannel.configureBlocking(false); while(true){ SocketChannel socketChannel = serverSocketChannel.accept(); if(socketChannel != null){ receiveFile(socketChannel); } } } catch (IOException e) { e.printStackTrace(); } } }); th.run(); } catch (Exception ex) { ex.printStackTrace(); } } public static void receiveFile(SocketChannel socketChannel) throws IOException { final Path filePath = Paths.get("test"); //要将接收的文件写到当前目录的test文件中 FileChannel fileChannel = (FileChannel.open(filePath, EnumSet.of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING))); //先获取文件大小,这里我约定前8个字节表示文件大小 ByteBuffer buf = ByteBuffer.allocate(8); socketChannel.read(buf); buf.flip(); long fileSize = buf.getLong(); System.out.println("fileSize :" + fileSize); //接收文件内容 fileChannel.transferFrom(socketChannel, 0, fileSize); fileChannel.close(); }

2.客户端代码

public static void main(String[] args) {

        if(args.length != 3){
            System.out.println("Usage :  java -jar ClientTcpSend.jar ipaddress port  filename");
            return;
        }

        SocketChannel socketChannel;
        try {
            socketChannel = SocketChannel.open();
            socketChannel.connect(new InetSocketAddress(args [0], Integer.parseInt(args[1])));

            final Path filePath = Paths.get(args[2]);

            FileChannel fileChannel = (FileChannel.open(filePath, 
                    EnumSet.of(StandardOpenOption.READ)));

            long start = System.currentTimeMillis();

            //用来发送文件大小
            ByteBuffer buf = ByteBuffer.allocate(8);
            buf.asLongBuffer().put(fileChannel.size());
            socketChannel.write(buf);

            //发送文件内容
            fileChannel.transferTo(0, fileChannel.size(), socketChannel);
            fileChannel.close();
            socketChannel.close();

            long end = System.currentTimeMillis();

            System.out.println("Total use " + (end - start) + "ms");

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


    }
}

3.测试过程

将两个jar包传到不同的服务器中,在服务端启动监听
java -jar NIOServer.jar 12345
在客户端向服务端发送文件,如下:
java -jar java -jar NIOClient.jar 192.168.11.102 12345 spark-1.3.0-cdh5.4.4.tar.gz

4.测试结果

服务器端

客户端

Read/Write发送测试

1.测试过程

使用TCP建立socket连接,然后从客户端向服务端发送。代码太简单就不粘贴了。

2.测试结果

客户端

服务端:略

总结

由上述测试可以看到NIO与Read/Write在网络传输文件过程中的差异。NIO消除了CPU的数据拷贝,直接在内核空间中,将数据从文件缓冲区发送到网卡缓冲区中进行发送。而传统模式下数据从文件传输到网络需要4次数据拷贝,4次上下文切换和2次系统调用。如下:

传统模式下发送文件过程

NIO transferTo/transferFrom发送文件过程

Java NIO的transferTo/transferFrom与read/write方式文件网络数据传输测试对比
Tagged on:             

发表评论

电子邮件地址不会被公开。 必填项已用*标注