Netty(24)Netty中的零拷贝文件传输

Netty中的零拷贝文件传输利用了操作系统提供的零拷贝功能,使得文件数据可以直接从文件系统传输到网络,而无需经过用户空间。这大大提高了数据传输的效率,减少了CPU的使用和内存的拷贝操作。

Netty通过 FileRegionDefaultFileRegion 类来实现零拷贝文件传输。以下是详细的步骤和代码示例:

服务器端实现

  1. 创建服务器引导程序(ServerBootstrap)
java 复制代码
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class ZeroCopyFileServer {
    public static void main(String[] args) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class)
             .childHandler(new ZeroCopyFileServerInitializer());

            b.bind(8080).sync().channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
  1. 初始化服务器管道(ChannelPipeline)
java 复制代码
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

public class ZeroCopyFileServerInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ch.pipeline().addLast(new LoggingHandler(LogLevel.INFO));
        ch.pipeline().addLast(new ZeroCopyFileServerHandler());
    }
}
  1. 实现文件传输处理器(ChannelInboundHandlerAdapter)
java 复制代码
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.DefaultFileRegion;

import java.io.RandomAccessFile;

public class ZeroCopyFileServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        RandomAccessFile file = new RandomAccessFile("path/to/file.txt", "r");
        long fileLength = file.length();

        DefaultFileRegion region = new DefaultFileRegion(file.getChannel(), 0, fileLength);
        ctx.writeAndFlush(region).addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                file.close();
                ctx.close();
            }
        });
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

客户端实现

客户端需要接收文件数据并进行处理。

  1. 创建客户端引导程序(Bootstrap)
java 复制代码
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

public class ZeroCopyFileClient {
    public static void main(String[] args) throws Exception {
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
             .channel(NioSocketChannel.class)
             .handler(new ZeroCopyFileClientInitializer());

            b.connect("localhost", 8080).sync().channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully();
        }
    }
}
  1. 初始化客户端管道(ChannelPipeline)
java 复制代码
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

public class ZeroCopyFileClientInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ch.pipeline().addLast(new LoggingHandler(LogLevel.INFO));
        ch.pipeline().addLast(new ZeroCopyFileClientHandler());
    }
}
  1. 实现文件接收处理器(ChannelInboundHandlerAdapter)
java 复制代码
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.io.FileOutputStream;
import java.io.RandomAccessFile;

public class ZeroCopyFileClientHandler extends ChannelInboundHandlerAdapter {
    private FileOutputStream fos;
    private RandomAccessFile file;

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        file = new RandomAccessFile("received_file.txt", "rw");
        fos = new FileOutputStream(file.getFD());
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof ByteBuf) {
            ByteBuf buf = (ByteBuf) msg;
            byte[] bytes = new byte[buf.readableBytes()];
            buf.readBytes(bytes);
            fos.write(bytes);
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        fos.close();
        file.close();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

在上述代码中,服务器端通过 DefaultFileRegion 实现了零拷贝文件传输。客户端接收到文件数据并将其写入到本地文件。通过这种方式,可以有效地减少数据在用户空间和内核空间之间的拷贝次数,提高传输效率。

相关推荐
Victor3564 小时前
Netty(23)Netty的负载均衡和高可用性如何实现?
后端
武昌库里写JAVA4 小时前
Java设计模式-(创建型)抽象工厂模式
java·vue.js·spring boot·后端·sql
程序员爱钓鱼6 小时前
Node.js 编程实战:图像与文件上传下载
前端·后端·node.js
程序员爱钓鱼6 小时前
Node.js 编程实战:日志管理与分析
后端·面试·node.js
吴佳浩11 小时前
Python入门指南(五) - 为什么选择 FastAPI?
后端·python·fastapi
GoGeekBaird12 小时前
分享几个使用Nano Banana Pro 画信息图的提示词
后端·github
shoubepatien12 小时前
JAVA -- 08
java·后端·intellij-idea
yangminlei12 小时前
springboot pom.xml配置文件详细解析
java·spring boot·后端
黄俊懿12 小时前
【深入理解SpringCloud微服务】Seata(AT模式)源码解析——全局事务的提交
java·后端·spring·spring cloud·微服务·架构·架构师