`

Netty源码学习-FileRegion

阅读更多

今天看org.jboss.netty.example.http.file.HttpStaticFileServerHandler.java
可以直接往channel里面写入一个FileRegion对象,而不需要相应的encoder:

		//pipeline(没有诸如“FileRegionEncoder”的handler):
		public ChannelPipeline getPipeline() throws Exception {
			ChannelPipeline pipeline = pipeline();
			pipeline.addLast("decoder", new HttpRequestDecoder());
			pipeline.addLast("aggregator", new HttpChunkAggregator(65536));
			pipeline.addLast("encoder", new HttpResponseEncoder());
			pipeline.addLast("chunkedWriter", new ChunkedWriteHandler());

			pipeline.addLast("handler", new HttpStaticFileServerHandler());
			return pipeline;
		}
		
		public class HttpStaticFileServerHandler extends SimpleChannelUpstreamHandler {
			public void messageReceived...{
				RandomAccessFile raf = new RandomAccessFile(file, "r");
				long fileLength = raf.length();

				HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
				setContentLength(response, fileLength);
				setContentTypeHeader(response, file);
				setDateAndCacheHeaders(response, file);

				Channel ch = e.getChannel();

				// Write the initial line and the header.
				ch.write(response);

				// Write the content.
				// No encryption - use zero-copy.
				final FileRegion region =
						new DefaultFileRegion(raf.getChannel(), 0, fileLength);
				
				//直接写入FileRegion
				ch.write(region);
			}
		}
		


这是为什么?往channel里面写的数据最后不是都要转成ChannelBuffer吗?

我们一步步的分析:
ch.write(region)会触发downstream事件(把region“装入”MessageEvent),
会一路经过各个handler,最后去到“sink”:

	//我们以NioServerSocketPipelineSink为例:
	private static void handleAcceptedSocket(ChannelEvent e) {
		  if (e instanceof MessageEvent) {
				MessageEvent event = (MessageEvent) e;
				NioSocketChannel channel = (NioSocketChannel) event.getChannel();
				boolean offered = channel.writeBufferQueue.offer(event);
				assert offered;
				channel.worker.writeFromUserCode(channel);
			}
    }

	//最终的写操作在AbstractNioWorker(只保留关键代码):
    protected void write0(AbstractNioChannel<?> channel) {
	        final WritableByteChannel ch = channel.channel;
	        final Queue<MessageEvent> writeBuffer = channel.writeBufferQueue;
			channel.currentWriteEvent = evt = writeBuffer.poll();
			
			/*关键在这里:把FileRegion封装成一个SendBuffer,
			SendBuffer的transferTo调用的是FileRegion的transferTo方法,
			而这个方法调用的是FileChannel的transferTo方法:
			This method is potentially much more efficient than a simple loop that reads from this channel and writes to the target channel. Many operating systems can transfer bytes directly from the filesystem cache to the target channel without actually copying them.
			大体意思就是“Java NIO Channel to Channel Transfers”不需要内存复制,速度更快
			*/
	        channel.currentWriteBuffer = buf = sendBufferPool.acquire(evt.getMessage());
			buf.transferTo(ch);
	}

	//这里证明了,往channel写入的数据,类型既可以是ChannelBuffer,也可以是FileRegion
	SendBuffer acquire(Object message) {
        if (message instanceof ChannelBuffer) {
            return acquire((ChannelBuffer) message);
        } else if (message instanceof FileRegion) {
            return acquire((FileRegion) message);
        }

        throw new IllegalArgumentException(
                "unsupported message type: " + message.getClass());
    }

	private SendBuffer acquire(FileRegion src) {
        if (src.getCount() == 0) {
            return EMPTY_BUFFER;
        }
        return new FileSendBuffer(src);
    }
	
	class FileSendBuffer {	
		private final FileRegion file;
		public long transferTo(WritableByteChannel ch) throws IOException {
				long localWrittenBytes = file.transferTo(ch, writtenBytes);
				writtenBytes += localWrittenBytes;
				return localWrittenBytes;
			}
	}

	class DefaultFileRegion...{
		 private final FileChannel file;
		 public long transferTo(WritableByteChannel target, long position) throws IOException {
			return file.transferTo(this.position + position, count, target);
		}
	}




最后,记录一下java NIO对大文件的读写方法:

java.nio.channels.FileChannel的map方法可以把FileChannel“包装”成MappedByteBuffer:
public abstract MappedByteBuffer map(FileChannel.MapMode mode,
                   long position,
                   long size)

对于大文件,转成MappedByteBuffer再读写,速度更快
举例:

public class ReadingHugeFilesUsingMemoryMappedBuffer {
    /**
     * use a MappedByteBuffer to wrap a huge file. Using a MappedByteBuffer does
     * not load the file in JVM but reads it directly off the file system
     * memory. The file can be opened in read, write or private mode.
     */
    // to test you can use any video movie file if you dont have any other large
    // file for testing.
    private static String hugeFile = "A Huge File";
 
    public static void main(String[] args) throws IOException {
        File file = new File(hugeFile);
        FileChannel fileChannel = new RandomAccessFile(file, "r").getChannel();
        MappedByteBuffer buffer = fileChannel.map(
                FileChannel.MapMode.READ_ONLY, 0, fileChannel.size());
        // the buffer now reads the file as if it were loaded in memory. note
        // that for smaller files it would be faster
        // to just load the file in memory
        // lets see if this buffer is loaded fully into memory
        System.out.println(buffer.isLoaded());
        // the mappedbytebuffer can be used as a normal buffer to do read and/or
        // write operations
        // read the size
        System.out.println(buffer.capacity());
     
    }
}












0
0
分享到:
评论
1 楼 萨琳娜啊 2018-07-10  
Java读源码之Netty深入剖析
网盘地址:https://pan.baidu.com/s/1pdLNtJGkOSd1fGBT_chAqA 密码: 2kfw
备用地址(腾讯微云):https://share.weiyun.com/5Bs3HcR 密码:uu95be

JavaCoder如果没有研究过Netty,那么你对Java语言的使用和理解仅仅停留在表面水平,如果你要进阶,想了解Java服务器的深层高阶知识,Netty绝对是一个必须要过的门槛。

本课程带你从一个Socket例子入手,一步步深入探究Netty各个模块的源码,深入剖析Netty的工作流程和源码设计,让你不但“真懂”也要“会用”

相关推荐

    Netty源码教程-3

    在本节"Netty源码教程-3"中,我们将深入探讨Netty这一高性能、异步事件驱动的网络应用程序框架。Netty广泛应用于各种分布式系统、服务器和客户端应用,尤其在处理高并发、低延迟的网络通信场景下,其优势尤为突出。...

    Netty源码教程-1

    这个“Netty源码教程-1”可能是系列教程的第一部分,旨在帮助开发者深入理解Netty的工作原理和内部机制。让我们通过以下几个关键知识点来探索Netty的核心特性。 1. **异步事件驱动模型** Netty采用非阻塞I/O模型,...

    Netty权威指南源码-含jar包,导入eclipse直接使用

    在Eclipse中使用Netty源码,你可以深入了解其内部实现,学习如何构建网络服务,理解异步编程和事件驱动模型,这对于提升Java网络编程的能力非常有帮助。同时,有了预封装的jar包,你可以直接运行和测试示例代码,...

    netty-4.1.19.Final

    这个"Netty-4.1.19.Final"版本是该框架的一个稳定版本,提供了所有功能的一体化打包,包括源代码,方便开发者进行深入学习和定制。 Netty 的核心特性主要包括: 1. **异步事件驱动**:Netty 使用非阻塞I/O模型,...

    netty实战-netty-thing.zip

    5. **零拷贝**:Netty实现了零拷贝技术,通过DirectByteBuffer和FileRegion,减少了数据在内核和用户空间之间的复制,提升了性能。 6. **协议支持**:Netty内置了大量的协议解码器和编码器,如HTTP、WebSocket、FTP...

    netty-code:netty包源码-源码包

    Netty 是一个高性能、异步事件驱动...通过对Netty源码的学习,开发者不仅可以掌握网络编程的最佳实践,还能深入了解Java并发编程、内存管理以及性能优化等核心技能,对提升个人技术水平和解决实际问题具有极大的帮助。

    netty实战和源码解读-mini-netty.zip

    “mini-netty-master”项目的源码可能会涵盖上述的一些或全部知识点,通过学习和分析这个简化版的实现,你可以更好地理解Netty的设计思想和使用方式,进阶到源码阅读将有助于深入理解Netty的内部工作原理。...

    netty-4.1源代码

    这个“netty-4.1源代码”压缩包包含了Netty框架的4.1版本的源码,对于理解Netty的工作原理、学习网络编程以及优化性能有极大的帮助。 Netty 的核心组件包括: 1. **ByteBuf**: Netty 自定义的字节缓冲区,比Java ...

    netty-4.0.41-2016-9-29官网下载

    这个“netty-4.0.41.Final”文件可能包含了Netty 4.0.41稳定版本的源码、编译后的JAR文件、文档以及示例代码等。开发者可以使用这些资源进行学习和开发,或者集成到自己的项目中,利用Netty的强大功能构建高性能的...

    netty-4.1 源码包

    通过分析和学习Netty 4.1的源码,我们可以深入理解其设计理念,如如何实现高效的并发处理,如何优雅地处理I/O事件,以及如何设计灵活的网络协议处理器。这对于开发高性能网络应用,特别是分布式系统和微服务架构,...

    netty-code源码

    通过深入学习和分析"netty-code"源码,你可以了解Netty如何处理网络通信的各个阶段,包括连接建立、数据传输、异常处理等,这对于开发高性能的网络应用非常有帮助。同时,源码中的示例可以帮助你更好地理解和运用...

    nettymaster

    "Netty-in-Action-Master" 的源码可能涵盖了这些知识点的实践应用,通过学习这些源码,开发者能更深入地理解 Netty 的工作原理,并将其应用到实际的网络服务开发中。这个项目可能包含各种示例,如简单的 TCP/UDP ...

    Netty实战相关代码-nia-samples-parent.zip

    这个"Netty实战相关代码-nia-samples-parent.zip"压缩包包含了一个名为"nia-samples-parent-master"的项目,它很可能是Netty实战教程或示例代码的源码仓库。 在深入讲解Netty的知识点之前,我们先了解一下这个项目...

    netty权威指南和源码

    压缩包子文件 "netty权威指南完整版+源码" 提供了完整的书籍资源和Netty的源代码,这将帮助开发者在理论学习的同时,结合实际代码进行实践,加深理解。 现在,让我们详细讨论Netty的一些核心知识点: 1. **事件...

    Netty权威指南 第2版 + 源码

    《Netty权威指南 第2版》是学习和理解Netty的核心参考资料,结合源码分析能更深入地掌握其实现原理。 该书完整版包含了详细的书签目录,方便读者迅速定位到所需章节,深入理解Netty的设计理念和使用技巧。以下将对...

    learning-netty.zip

    这个“learning-netty.zip”压缩包包含了一份Netty的学习笔记,重点在于代码学习和源码分析,基于Netty的4.1版本。下面将围绕Netty的核心概念、特性、以及如何通过学习笔记来深入理解Netty进行详细阐述。 1. **...

    netty-代码.zip

    这个项目可能包含了各种Netty的基础和高级用法,对于学习和理解Netty的工作原理非常有帮助。 Netty 的核心特性包括: 1. **异步事件驱动**:Netty 使用非阻塞I/O模型,基于Java NIO(非阻塞I/O)构建,能够高效地...

    netty权威指南第二版随书示例源码

    7. **零拷贝**:Netty 通过直接 ByteBuf 和 FileRegion 实现零拷贝,减少了不必要的内存复制,提高了性能。 8. **异常处理**:Netty 提供了统一的异常处理机制,可以方便地捕获和处理各种网络通信中的异常。 ...

    javaNetty仿微信源码

    Java Netty 仿微信源码解析 在Java领域,Netty是一个高性能、异步事件驱动的网络应用程序框架,常用于...学习和理解Java Netty仿微信源码,不仅能够提升网络编程能力,还能为开发类似的实时通讯应用打下坚实的基础。

    《Netty 实战》源码

    《Netty实战》源码是学习和研究Netty框架的重要参考资料。Netty是一个高性能、异步事件驱动的网络应用程序框架,适用于开发服务器和客户端的Java应用。它为高并发、低延迟的网络应用提供了强大的支持,广泛应用于...

Global site tag (gtag.js) - Google Analytics