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

相关推荐
码事漫谈2 小时前
1999年的电商前夜和2026年的AI前夜 历史押韵但从不重复
后端
Conan在掘金2 小时前
鸿蒙报错速查:arkts-strict-typing Property does not exist on type 'object',object 装函数就炸,根因 + 真解法
后端
颜酱2 小时前
01 | 骨架搭建:FastAPI + Vue 跑通第一个 SSE 流式问答
前端·人工智能·后端
程序员cxuan3 小时前
Grok Build 被众人唾骂,结果老马把它开源了
人工智能·后端·程序员
从零开始的代码生活_3 小时前
C++ 继承详解:访问控制、对象模型、菱形继承与设计取舍
开发语言·c++·后端·学习·算法
Conan在掘金3 小时前
�鸿蒙报错速查:Cannot find name 'require',禁用 require(),根因 + 真解法
后端
隔窗听雨眠3 小时前
Spring Boot在云原生时代的编程范式革新研究
spring boot·后端·云原生
一朵小花3 小时前
记一次Docker 容器 NFS 文件写入延迟排查过程
后端
FF2501_940228585 小时前
Grid 构建月历网格:7 列模板 + 日期占位算法
后端·华为·harmonyos·鸿蒙系统
神奇小汤圆5 小时前
线程池的 DiscardPolicy 为什么是「静默杀手」?一个生产事故的完整复盘
后端