当前位置:首页 > 开发 > 编程语言 > 网络编程 > 正文

Netty源码学习-FileRegion

发表于: 2013-12-31   作者:bylijinnan   来源:转载   浏览:
摘要: 今天看org.jboss.netty.example.http.file.HttpStaticFileServerHandler.java 可以直接往channel里面写入一个FileRegion对象,而不需要相应的encoder: //pipeline(没有诸如“FileRegionEncoder”的handler): public ChannelPipeline ge

今天看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());
     
    }
}












Netty源码学习-FileRegion

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

编辑推荐
背景 最忌工作中接触到Netty相关应用场景,之前看过mima的部分源码,所以最近看了Netty的部分源码和
类结构图: 不了解Executor接口原理的可以查看concurrent包中的api介绍,这里只介绍Netty中EventExe
Transport API的核心: Channel接口 类图表示Channel含有Pipeline和Config接口,pipeline上一节有所
Netty是一个基于JAVA NIO类库的异步通信框架,它的架构特点是:异步非阻塞、基于事件驱动、高性能、
先看下netty的channel对象关联关系。channel是由channelfactory来创建的,channelfactory又分为clie
感谢网友【黄亿华】投递本稿。 上一篇文章我们概要介绍了Netty的原理及结构,下面几篇文章我们开始
上一篇文章我们概要介绍了Netty的原理及结构,下面几篇文章我们开始对Netty的各个模块进行比较详细
netty里面最重要的应该是ChannelHandler,这个里面也是用户编程直接打交道的接口,也是串行于Channe
本文采用版本为Jboss Netty-3.2.4.Final,Jboss Netty示例example、几十页的user guide是快速学习的
本文为原创,转载请注明出处 netty 4源码分析-write Netty的写操作由两个步骤组成: Write:将msg存
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号