使用 NIO 实现“客户端向服务端发送文件”功能

x33g5p2x  于2022-05-22 转载在 其他  
字(2.3k)|赞(0)|评价(0)|浏览(285)

一 服务端代码

public static void server() throws IOException {
    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    FileChannel outFileChannel = FileChannel.open(Paths.get("g:\\navicat1.chm"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
    // 将服务绑定在 8888 端口上
    serverSocketChannel.bind(new InetSocketAddress(8888)); // 默认服务的 ip 就是本机ip
    // 创建与客户端建立连接的 SocketChannel 对象
    SocketChannel sChannel = serverSocketChannel.accept();
    System.out.println("连接成功...");

    long start = System.currentTimeMillis();
    // 分配指定大小的缓冲区
    ByteBuffer buf = ByteBuffer.allocate(1024);
    // 接收客户端发送的文件,并保存到本地
    while (sChannel.read(buf) != -1) {
        buf.flip();
        outFileChannel.write(buf);
        buf.clear();
    }
    System.out.println("接收成功!");

    sChannel.close();
    outFileChannel.close();
    serverSocketChannel.close();
    long end = System.currentTimeMillis();
    System.out.println("服务端接收文件耗时:" + (end - start));
}

二 客户端代码

public static void client() throws IOException {
    FileChannel inFileChannel = FileChannel.open(Paths.get("g:\\navicat.chm"), StandardOpenOption.READ);
    // 创建与服务端建立连接的 SocketChannel 对象
    SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8888));
    // 分配指定大小的缓冲区
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    long start = System.currentTimeMillis();
    // 读取本地文件,并发送到服务端
    while (inFileChannel.read(buffer) != -1) {
        buffer.rewind();
        socketChannel.write(buffer);
        buffer.clear();
    }
    if (inFileChannel != null) inFileChannel.close();
    if (socketChannel != null) socketChannel.close();
    long end = System.currentTimeMillis();
    System.out.println("客户端发送文件耗时:" + (end - start));
}

三 测试

1 服务端运行结果

连接成功...

接收成功!

服务端接收文件耗时:385

2 客户端运行结果

客户端发送文件耗时:385

3 说明

以上客户端和服务端虽然都使用了 NIO 的处理方式,但默认都使用了非直接缓冲区,因此效率较低。

四 客户端代码改进

1 说明

将客户端代码改造成直接缓冲区

2 代码

public static void client2() throws IOException {
    long start = System.currentTimeMillis();
    // 创建与服务端建立连接的 SocketChannel 对象
    SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8888));
    FileChannel inFileChannel = FileChannel.open(Paths.get("g:\\navicat1.chm"), StandardOpenOption.READ);
    // 通过 inFileChannel.size() 获取文件的大小,从而在内核地址空间中开辟与文件大小相同的直接缓冲区
    inFileChannel.transferTo(0, inFileChannel.size(), socketChannel);
    if (inFileChannel != null) inFileChannel.close();
    if (socketChannel != null) socketChannel.close();
    long end = System.currentTimeMillis();
    System.out.println("客户端发送文件耗时:" + (end - start));
}

3 服务端运行结果

连接成功...

接收成功!

服务端接收文件耗时:109

4 客户端运行结果

客户端发送文件耗时:82

5 小结

通过结果对比,客户端使用了直接缓冲区后,传输的效率明显提升了。

相关文章