当前位置: 首页 > news >正文

第一章Netty,NIO零拷贝详细实现代码

基于前文对 ‌NIO 零拷贝原理‌(sendfile 与 mmap)及‌高并发场景‌的讨论,以下是两种核心零拷贝技术的详细 Java 实现代码。

先看一段传统IO模型的文件拷贝代码:

packagecom.example.demo;importjava.io.File;importjava.io.IOException;importjava.io.RandomAccessFile;importjava.net.Socket;publicclassFileNioTest{publicstaticvoidmain(String[]args)throwsIOException{Filef=newFile("netty.txt");RandomAccessFilefile=newRandomAccessFile(f,"r");byte[]buf=newbyte[(int)f.length()];intread=file.read(buf);Socketsocket=newSocket();socket.getOutputStream().write(buf);}}

传统IO工作流程:



一、 基于 transferTo 的文件网络传输(推荐)

这是最纯粹的零拷贝,适用于‌静态资源服务器‌或‌大文件上传/下载‌。数据直接在内核态从 Page Cache 传输到 Socket Buffer,不经过用户态。

1. 服务端代码(发送文件)

importjava.io.FileInputStream;importjava.net.InetSocketAddress;importjava.nio.channels.FileChannel;importjava.nio.channels.ServerSocketChannel;importjava.nio.channels.SocketChannel;publicclassZeroCopyServer{publicstaticvoidmain(String[]args)throwsException{// 1. 创建 ServerSocketChannelServerSocketChannelserverSocketChannel=ServerSocketChannel.open();serverSocketChannel.bind(newInetSocketAddress(8080));System.out.println("Server started on port 8080...");while(true){// 2. 接受连接SocketChannelsocketChannel=serverSocketChannel.accept();// 3. 获取文件通道FileChannelfileChannel=newFileInputStream("large_file.dat").getChannel();// 4. 【核心】零拷贝传输// transferTo 底层调用 sendfile,数据不经过用户空间longtransferred=fileChannel.transferTo(0,fileChannel.size(),socketChannel);System.out.println("Total bytes transferred: "+transferred);// 5. 关闭资源fileChannel.close();socketChannel.close();}}}

2. 客户端代码(接收文件)

importjava.io.FileOutputStream;importjava.net.InetSocketAddress;importjava.nio.channels.FileChannel;importjava.nio.channels.SocketChannel;publicclassZeroCopyClient{publicstaticvoidmain(String[]args)throwsException{// 1. 连接服务器SocketChannelsocketChannel=SocketChannel.open();socketChannel.connect(newInetSocketAddress("localhost",8080));// 2. 获取文件输出通道FileChannelfileChannel=newFileOutputStream("received_file.dat").getChannel();// 3. 读取数据并写入文件// 注意:客户端接收通常仍涉及一次从内核到用户空间的拷贝(除非使用 DirectBuffer + write)// 但服务端发送已实现零拷贝,整体性能显著提升longbytesRead=fileChannel.transferFrom(socketChannel,0,Long.MAX_VALUE);System.out.println("Total bytes received: "+bytesRead);// 4. 关闭资源fileChannel.close();socketChannel.close();}}

二、 基于 MappedByteBuffer 的大文件随机读写

适用于‌数据库索引‌、‌日志分析‌等需要频繁随机访问大文件的场景。通过内存映射,避免传统 read/write 的系统调用开销。

1. 写入大文件示例

importjava.io.RandomAccessFile;importjava.nio.MappedByteBuffer;importjava.nio.channels.FileChannel;publicclassMappedFileWriter{publicstaticvoidmain(String[]args)throwsException{StringfilePath="mapped_large_file.dat";longfileSize=1024*1024*100;// 100MB// 1. 创建 RandomAccessFile 和 FileChannelRandomAccessFileraf=newRandomAccessFile(filePath,"rw");FileChannelchannel=raf.getChannel();// 2. 【核心】内存映射// MapMode.READ_WRITE: 读写模式// position: 0, size: fileSizeMappedByteBuffermappedBuffer=channel.map(FileChannel.MapMode.READ_WRITE,0,fileSize);// 3. 直接操作内存,如同操作数组for(inti=0;i<1024;i++){mappedBuffer.putInt(i*4,i);// 在偏移量 i*4 处写入整数 i}// 4. 强制刷新到磁盘(可选,确保数据持久化)mappedBuffer.force();System.out.println("Data written to mapped file.");// 5. 关闭资源channel.close();raf.close();}}

2. 读取大文件示例

importjava.io.RandomAccessFile;importjava.nio.MappedByteBuffer;importjava.nio.channels.FileChannel;publicclassMappedFileReader{publicstaticvoidmain(String[]args)throwsException{StringfilePath="mapped_large_file.dat";// 1. 创建 RandomAccessFile 和 FileChannelRandomAccessFileraf=newRandomAccessFile(filePath,"r");FileChannelchannel=raf.getChannel();// 2. 内存映射(只读模式)MappedByteBuffermappedBuffer=channel.map(FileChannel.MapMode.READ_ONLY,0,channel.size());// 3. 随机读取数据intvalue=mappedBuffer.getInt(0);// 读取偏移量 0 处的整数System.out.println("Value at offset 0: "+value);intvalueAt1024=mappedBuffer.getInt(1024*4);System.out.println("Value at offset 4096: "+valueAt1024);// 4. 关闭资源channel.close();raf.close();}}

三、 关键注意事项

‌资源关闭‌:FileChannel 和 SocketChannel 必须显式关闭,否则会导致文件描述符泄漏。
‌内存映射释放‌:MappedByteBuffer 占用的堆外内存不会立即被 GC 回收。若需手动释放,可借助 sun.misc.Cleaner(非官方 API,需谨慎使用)或通过反射调用 clean() 方法。
‌小文件性能‌:对于极小文件(< 1KB),零拷贝的系统调用开销可能高于传统 I/O,此时传统 read/write 可能更优。
‌平台差异‌:transferTo 在 Linux 下性能最佳(完整零拷贝),在 Windows 下可能退化为部分拷贝实现。

http://www.gsyq.cn/news/1628518.html

相关文章:

  • NAFNet图像恢复终极指南:如何用AI让模糊照片变清晰
  • 即触 AI PPT:从文档到PPT,用这个工具就够了
  • ICM-42605六轴IMU与PIC18F2515实现高精度姿态追踪
  • STM32F767ZG与KMX63传感器融合开发指南
  • 基于TC78H660FTG的高效直流电机驱动系统设计
  • 如何快速安装和使用 Liberation Fonts:开源字体的完整指南 [特殊字符]
  • TC78H653FTG与PIC18F45K80驱动直流有刷电机方案详解
  • 高校生常用的AI论文工具是哪款?
  • GitHubDesktop2Chinese:3分钟实现GitHub Desktop中文汉化的完整指南
  • 【NASA级代码可信性认证实践】:AI审查如何通过ISO/IEC 25010质量模型验证?
  • 面向高标准农田巡检:基于YOLO的无人机智能分析系统落地实战
  • 朋友圈广告适合什么商家 有没有效果?
  • GEO优化系统源码搭建:智能文章生成开发实战(附完整源码)
  • 终极指南:使用WorkshopDL免费下载Steam创意工坊模组
  • 直流有刷电机高效驱动方案:TC78H653FTG与CEC1302解析
  • 如何用Ollama+OpenWebUI本地部署Qwen2大模型
  • CBCX外汇服务节奏顺手吗?清楚吗?
  • 跨越设计与开发鸿沟:HTML转Figma工具的技术实现与应用实践
  • system_server或Zygote进程死亡后,Zygote fork出的app子进程销毁流程
  • Obsidian高效笔记的终极神器:Templater插件完全指南
  • 从零部署到实战:深度解析CyberStrikeAI自动化安全测试平台
  • VMPDump终极指南:如何快速破解VMProtect保护的Windows程序
  • 用过才敢说!盘点2026年当红之选的AI论文网站
  • Figma中文插件:3步实现Figma界面全中文化,设计师效率提升50%
  • 自建房装电梯井道动工前,先做好这几件事
  • 基于FOC的无刷电机控制方案设计与实现
  • 重新定义Windows界面美学:DWMBlurGlass技术原理与实战应用
  • PiliPlus:为什么这个跨平台B站客户端能让你彻底告别官方App的烦恼?
  • CBCX外汇的在线支持值不值得了解?
  • 2026年7月雨水收集系统厂家推荐指南:雨水收集系统、化粪池、水泥涵管、净水设备本土厂家实测甄选