首先客户端连接到服务端时服务端会开启一个线程,不断的监听客户端的操作。

这个线程的执行操作在NioEventLoop的run方法中,其实操作是在processSelectedKeys中,监听是否进行读操作

protected void run() {
        for (;;) {
            try {
                switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {
                    case SelectStrategy.CONTINUE:
                        continue;
                    case SelectStrategy.SELECT:
                        select(wakenUp.getAndSet(false));
                        if (wakenUp.get()) {
                            selector.wakeup();
                        }
                    default:
                        // fallthrough
                }

                cancelledKeys = 0;
                needsToSelectAgain = false;
                final int ioRatio = this.ioRatio;
                if (ioRatio == 100) {
                    processSelectedKeys();
                    runAllTasks();
                } else {
                    final long ioStartTime = System.nanoTime();
                    processSelectedKeys();
                    final long ioTime = System.nanoTime() - ioStartTime;
                    runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
                }

                if (isShuttingDown()) {
                    closeAll();
                    if (confirmShutdown()) {
                        break;
                    }
                }
            }
		}
    }
private void processSelectedKeys() {
        if (selectedKeys != null) {
            processSelectedKeysOptimized(selectedKeys.flip());
        } else {
            processSelectedKeysPlain(selector.selectedKeys());
        }
    }

判断selectedKeys数组中是否有值,其实就是read,write或accept事件

private void processSelectedKeysOptimized(SelectionKey[] selectedKeys) {
        for (int i = 0;; i ++) {
            final SelectionKey k = selectedKeys[i];
            if (k == null) {
                break;
            }
            selectedKeys[i] = null;

            final Object a = k.attachment();

            if (a instanceof AbstractNioChannel) {
                processSelectedKey(k, (AbstractNioChannel) a);
            } else {
                @SuppressWarnings("unchecked")
                NioTask<SelectableChannel> task = (NioTask<SelectableChannel>) a;
                processSelectedKey(k, task);
            }
        }
    }

主要判断int readyOps = k.readyOps();拿到的值是否是SelectionKey.OP_READ | SelectionKey.OP_ACCEPT

private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {
        final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe();
        if (!k.isValid()) {
            final EventLoop eventLoop;
            try {
                eventLoop = ch.eventLoop();
            } catch (Throwable ignored) {

            }

            if (eventLoop != this || eventLoop == null) {
                return;
            }

            unsafe.close(unsafe.voidPromise());
            return;
        }

        try {
            int readyOps = k.readyOps();

            if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
                unsafe.read();
                if (!ch.isOpen()) {
                    return;
                }
            }
            if ((readyOps & SelectionKey.OP_WRITE) != 0) {

                ch.unsafe().forceFlush();
            }
            if ((readyOps & SelectionKey.OP_CONNECT) != 0) {
                int ops = k.interestOps();
                ops &= ~SelectionKey.OP_CONNECT;
                k.interestOps(ops);

                unsafe.finishConnect();
            }
        } catch (CancelledKeyException ignored) {
            unsafe.close(unsafe.voidPromise());
        }
    }

如果int readyOps = k.readyOps();拿到的值是SelectionKey.OP_READ | SelectionKey.OP_ACCEPT就执行unsafe.read();

具体实现在AbstractNioByteChannel执行read操作

@Override
public final void read() {
	final ChannelConfig config = config();
	final ChannelPipeline pipeline = pipeline();
	final ByteBufAllocator allocator = config.getAllocator();
	final RecvByteBufAllocator.Handle allocHandle = recvBufAllocHandle();
	allocHandle.reset(config);

	ByteBuf byteBuf = null;
	boolean close = false;
	try {
		do {
			byteBuf = allocHandle.allocate(allocator);
			allocHandle.lastBytesRead(doReadBytes(byteBuf));
			if (allocHandle.lastBytesRead() <= 0) {
				// nothing was read. release the buffer.
				byteBuf.release();
				byteBuf = null;
				close = allocHandle.lastBytesRead() < 0;
				break;
			}
			allocHandle.incMessagesRead(1);
			readPending = false;
			pipeline.fireChannelRead(byteBuf);
			byteBuf = null;
            } while (allocHandle.continueReading());

		allocHandle.readComplete();
		pipeline.fireChannelReadComplete();

		if (close) {
			closeOnRead(pipeline);
		}
	} catch (Throwable t) {
		handleReadException(pipeline, byteBuf, t, close, allocHandle);
	}
}

读取操作是在doReadBytes(byteBuf)中,具体实现是在NioSocketChannel中

@Override
    protected int doReadBytes(ByteBuf byteBuf) throws Exception {
        final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle();
        allocHandle.attemptedBytesRead(byteBuf.writableBytes());
        return byteBuf.writeBytes(javaChannel(), allocHandle.attemptedBytesRead());
    }

接下来的操作是在AbstractByteBuf的writeBytes中进行。

@Override
    public int writeBytes(ScatteringByteChannel in, int length) throws IOException {
        ensureAccessible();
        ensureWritable(length);
        int writtenBytes = setBytes(writerIndex, in, length);
        if (writtenBytes > 0) {
            writerIndex += writtenBytes;
        }
        return writtenBytes;
    }

读取数据操作是在setBytes函数中进行的,一般实现是在PooledUnsafeDirectByteBuf类中

 @Override
    public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
        checkIndex(index, length);
        ByteBuffer tmpBuf = internalNioBuffer();
        index = idx(index);
        tmpBuf.clear().position(index).limit(index + length);
        try {
            return in.read(tmpBuf);
        } catch (ClosedChannelException ignored) {
            return -1;
        }
    }

在这里我们可以看到操作in.read(tmpBuf),这个操作就是NIO的读取数据操作了,in是SocketChannel对象,将数据读取到缓存中去,完成数据的读取过程。

【Netty源码分析】数据读取过程的更多相关文章

  1. lucene源码分析(2)读取过程实例

    1.官方提供的代码demo Analyzer analyzer = new StandardAnalyzer(); // Store the index in memory: Directory di ...

  2. Netty源码分析第5章(ByteBuf)---->第10节: SocketChannel读取数据过程

    Netty源码分析第五章: ByteBuf 第十节: SocketChannel读取数据过程 我们第三章分析过客户端接入的流程, 这一小节带大家剖析客户端发送数据, Server读取数据的流程: 首先 ...

  3. 【Netty源码分析】发送数据过程

    前面两篇博客[Netty源码分析]Netty服务端bind端口过程和[Netty源码分析]客户端connect服务端过程中我们分别介绍了服务端绑定端口和客户端连接到服务端的过程,接下来我们分析一下数据 ...

  4. Netty源码分析 (七)----- read过程 源码分析

    在上一篇文章中,我们分析了processSelectedKey这个方法中的accept过程,本文将分析一下work线程中的read过程. private static void processSele ...

  5. Netty源码分析第7章(编码器和写数据)---->第1节: writeAndFlush的事件传播

    Netty源码分析第七章: 编码器和写数据 概述: 上一小章我们介绍了解码器, 这一章我们介绍编码器 其实编码器和解码器比较类似, 编码器也是一个handler, 并且属于outbounfHandle ...

  6. Netty源码分析第7章(编码器和写数据)---->第2节: MessageToByteEncoder

    Netty源码分析第七章: Netty源码分析 第二节: MessageToByteEncoder 同解码器一样, 编码器中也有一个抽象类叫MessageToByteEncoder, 其中定义了编码器 ...

  7. Netty源码分析第7章(编码器和写数据)---->第5节: Future和Promies

    Netty源码分析第七章: 编码器和写数据 第五节: Future和Promise Netty中的Future, 其实类似于jdk的Future, 用于异步获取执行结果 Promise则相当于一个被观 ...

  8. 【Netty源码分析】客户端connect服务端过程

    上一篇博客[Netty源码分析]Netty服务端bind端口过程 我们介绍了服务端绑定端口的过程,这一篇博客我们介绍一下客户端连接服务端的过程. ChannelFuture future = boos ...

  9. Netty源码分析第7章(编码器和写数据)---->第3节: 写buffer队列

    Netty源码分析七章: 编码器和写数据 第三节: 写buffer队列 之前的小节我们介绍过, writeAndFlush方法其实最终会调用write和flush方法 write方法最终会传递到hea ...

  10. Netty源码分析第7章(编码器和写数据)---->第4节: 刷新buffer队列

    Netty源码分析第七章: 编码器和写数据 第四节: 刷新buffer队列 上一小节学习了writeAndFlush的write方法, 这一小节我们剖析flush方法 通过前面的学习我们知道, flu ...

随机推荐

  1. [NOI2011]道路修建

    题目描述 在 W 星球上有 n 个国家.为了各自国家的经济发展,他们决定在各个国家 之间建设双向道路使得国家之间连通.但是每个国家的国王都很吝啬,他们只愿 意修建恰好 n – 1 条双向道路. 每条道 ...

  2. codeforces 842C Ilya And The Tree

    Ilya is very fond of graphs, especially trees. During his last trip to the forest Ilya found a very ...

  3. 【luogu P4005 清华集训2017】小Y和地铁

    题目描述 小 Y 是一个爱好旅行的 OIer.一天,她来到了一个新的城市.由于不熟悉那里的交通系统,她选择了坐地铁. 她发现每条地铁线路可以看成平面上的一条曲线,不同线路的交点处一定会设有 换乘站 . ...

  4. scrapy常用命令(持续) | Commonly used Scrapy command list (con't)

    以下命令都是在CMD中运行,首先把路径定位到项目文件夹 ------------------------------------------------------------------------ ...

  5. MVC简单随笔

    MVC的具体含义是:model+view+controller,即模型+视图+控制它们各自处理自己的任务: (1)模型(model):模型持有所有的数据.状态和程序逻辑.模型独立于视图和控制器.(2) ...

  6. BigData-‘基于代价优化’究竟是怎么一回事?

    本文由  网易云发布. 本文具体讨论了Join基础算法的一种优化方案  – Runtime Filter,在本文最后还引申地聊了聊谓词 下推技术.同时,在本文文章开头,笔者引出了两个问题,SQL执行引 ...

  7. Ubuntu一些常用的软件安装及配置

    软件 安装 Vim echo "y" | sudo apt-get install vim 安装搜狗输入法 这个我在虚拟机里面尝试了好多遍,不断恢复备份然后重试.终于有了这个纯靠命 ...

  8. Axis2 webservice入门--Webservice的发布与调用

    一.Webservice发布 参考 http://www.cnblogs.com/demingblog/p/3263576.html 二.webservice 调用 部分参考:http://www.c ...

  9. Hibernate的条件查询的几种方式

    1. 第一种,用?占位符,如: //登录(用?占位符) public List<UserPO> LoginUser(UserPO up)throws Exception{ Session ...

  10. python字典无限遍历

    #无限遍历dict,通过key获取value,嵌套字典存在多个相同的key,可获取多个key class getValues(object): def __init__(self): pass #无限 ...