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 实现了零拷贝文件传输。客户端接收到文件数据并将其写入到本地文件。通过这种方式,可以有效地减少数据在用户空间和内核空间之间的拷贝次数,提高传输效率。

相关推荐
楚兴18 小时前
MacBook M1 安装 OpenClaw 完整指南
人工智能·后端
Java编程爱好者18 小时前
2026版Java面试八股文总结(春招+秋招+社招),建议收藏。
后端
朱昆鹏18 小时前
开源 Claude Code + Codex + 面板 的未来vibecoding平台
前端·后端·github
REDcker18 小时前
gRPC开发者快速入门
服务器·c++·后端·grpc
figo10tf18 小时前
Spring Boot项目集成Redisson 原始依赖与 Spring Boot Starter 的流程
java·spring boot·后端
zhangyi_viva18 小时前
Spring Boot(七):Swagger 接口文档
java·spring boot·后端
程序员敲代码吗18 小时前
Spring Boot与Tomcat整合的内部机制与优化
spring boot·后端·tomcat
牛奔19 小时前
如何理解 Go 的调度模型,以及 G / M / P 各自的职责
开发语言·后端·golang
chilavert31819 小时前
技术演进中的开发沉思-357:重排序(下)
java·后端
Boop_wu19 小时前
Spring生态
java·后端·spring