码迷,mamicode.com
首页 > Web开发 > 详细

Netty5概述-原创

时间:2015-05-28 12:43:14      阅读:192      评论:0      收藏:0      [点我收藏+]

标签:

private static void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {
        final NioUnsafe unsafe = ch.unsafe();
        if (!k.isValid()) {
            // close the channel if the key is not valid anymore
            unsafe.close(unsafe.voidPromise());
            return;
        }

        try {
            //得到当前的key关注的事件
            int readyOps = k.readyOps();
            // Also check for readOps of 0 to workaround possible JDK bug which may otherwise lead
            // to a spin loop
            //一个刚刚创建的NioServersocketChannel感兴趣的事件是0。
            if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {//可以读取操作  --对于serverSocket来说就是acceptor事件、对于socketChannel来说就是read事件 
                //INFO: channel类型为io.netty.channel.socket.nio.NioSocketChannel unsafe类型为io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe
                Object obj = k.attachment();//得到NioServerSocketChannel或者NioSocketChannel
                if(obj instanceof NioServerSocketChannel){
                    System.out.println(obj.getClass().getName()+ " 开始接收连接");
                }else{
                    System.out.println(obj.getClass().getName()+ " 开始接收字节");
                }
                //不同的socketChannel对于那个的unsafe是不同的。例如Server端的是messageUnsafe 而 clinet端是byteUnsafe
                unsafe.read();//对于接受链接或者read兴趣都会添加进入read操作调用serverSocket->NioMessageUnsafe
                if (!ch.isOpen()) {
                    // Connection already closed - no need to handle write.
                    return;
                }
            }
            if ((readyOps & SelectionKey.OP_WRITE) != 0) {//对于半包消息进行输出操作
                // Call forceFlush which will also take care of clear the OP_WRITE once there is nothing left to write
                ch.unsafe().forceFlush();
            }
            if ((readyOps & SelectionKey.OP_CONNECT) != 0) {
                // remove OP_CONNECT as otherwise Selector.select(..) will always return without blocking
                // See https://github.com/netty/netty/issues/924
                int ops = k.interestOps();
                ops &= ~SelectionKey.OP_CONNECT;
                k.interestOps(ops);

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

技术分享

这里我们以连接的建立(NioMessageUnsafe)为线索进行讲解。后续会有基于byte的unsafe进行讲解的(Unsafe不知道为啥要这么叫,本人也感到挺费解的,不过现在看来感觉就是一个工具对象。不要从名称上惧怕它)。下面来看NioMessageUnsafe的read方法进行讲解。直接讲代码(后面也会有图形讲解,方便大家理解):

 @Override
        public void read() {
            assert eventLoop().inEventLoop();
            if (!config().isAutoRead()) {
                removeReadOp();
            }

            final ChannelConfig config = config();
            //得到本次方法调用可以接收的连接数目
            final int maxMessagesPerRead = config.getMaxMessagesPerRead();
            final boolean autoRead = config.isAutoRead();
            final ChannelPipeline pipeline = pipeline();
            boolean closed = false;
            Throwable exception = null;
            try {
                for (;;) { 
                    //将msg从读取出来(SocketChannel-(common msg); serverSocketChannel(socketChannel msg))
                    int localRead = doReadMessages(readBuf);//readBuf仅仅是在本方法中起到缓冲统计的作用。不要多想哦!!
                    if (localRead == 0) {
                        break;
                    }
                    if (localRead < 0) {
                        closed = true;
                        break;
                    }
                    //每次读取的message的个数---
                    if (readBuf.size() >= maxMessagesPerRead | !autoRead) {
                        break;//避免一次性创建过多的连接个数
                    }
                }
            } catch (Throwable t) {
                exception = t;
            }

            int size = readBuf.size();
            for (int i = 0; i < size; i ++) {
                //对于server端来说,第一个handler为io.netty.bootstrap.ServerBootstrap$ServerBootstrapAcceptor
                ////针对所有的channel都会执行一个read操作;对于ServerSocketChannel ServerSocketChannel对应的pipeline的fireChannelRead方法
                //因为ServerSocketChannel的pipeline的第一个handler
                pipeline.fireChannelRead(readBuf.get(i));
            }
            readBuf.clear();//清空到的连接缓存
            pipeline.fireChannelReadComplete();

            if (exception != null) {
                if (exception instanceof IOException) {
                    // ServerChannel should not be closed even on IOException because it can often continue
                    // accepting incoming connections. (e.g. too many open files)
                    closed = !(AbstractNioMessageChannel.this instanceof ServerChannel);
                }

                pipeline.fireExceptionCaught(exception);
            }

            if (closed) {
                if (isOpen()) {
                    close(voidPromise());
                }
            }
        }
    }

下面让我们来看看上面这段代码中提到的

 int localRead = doReadMessages(readBuf);//doReadMessages是个抽象方法

技术分享

上代码:

 @Override
    protected int doReadMessages(List<Object> buf) throws Exception {//对于NioServerSocketChannel,它的读取操作,就是接受客户端的链接和创建NioSocketChannel
        SocketChannel ch = javaChannel().accept();//得到java远程的socketChannel对象。不要认为此处会阻塞,不会的因为connec事件发生了。所以会立即返回
        try {
            if (ch != null) {
                //进行包装,包装成netty的NioSocketChannel对象-将所有绑定socketChannel的处理线程
                buf.add(new NioSocketChannel(this, childEventLoopGroup().next(), ch));
                return 1;//每次仅仅处理一个,并且将得到连接对象放入到buf列表对象中进行保存
            }
        } catch (Throwable t) {
            logger.warn("Failed to create a new channel from an accepted socket.", t);

            try {
                ch.close();
            } catch (Throwable t2) {
                logger.warn("Failed to close a socket.", t2);
            }
        }
        return 0;
    }

Netty5概述-原创

标签:

原文地址:http://my.oschina.net/hotbain/blog/420941

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!