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

相关推荐
码事漫谈6 小时前
勿删
后端
IT_陈寒9 小时前
用了Proxy才发现以前的JavaScript白写了
前端·人工智能·后端
唐青枫10 小时前
别把 ArrayList 当成会自动管理内存的 List:Zig 动态数组从入门到实战
后端
鸿蒙开发10 小时前
我为 HarmonyOS 做了一个统一大模型 SDK:@hmkit/ai 正式开源
后端
猪是念来过倒10 小时前
Semaphore 与 RateLimiter:并发控制双雄详解
后端
掘金者阿豪10 小时前
异构数据同步最怕什么?不是同步慢,而是数据对不上
后端
程序员cxuan11 小时前
Claude 官方的学习教程,太强了。
人工智能·后端·程序员
老孙讲技术11 小时前
把工地遮挡和掉线接进项目部:setMessageCallback 订 alarm 与 deviceStatus
后端·物联网·音视频开发
老孙讲技术11 小时前
关店后有人进门,监控值班群却没响:用 setMessageCallback 订 human,再用 aiHuman 打开人形
后端·物联网·音视频开发
LEE11 小时前
原来 Claude Code 最厉害的工具,一行代码都不写
前端·后端