java netty之NioSocketChannel

来源:互联网 发布:淘宝运营直播 编辑:程序博客网 时间:2024/06/05 05:13

上一篇文章分析了NioServerSocketChannel,在这篇文章分析一下另外一种SocketChannel,其实也是调用accept之后创建的channel。。。

还是按照惯例来,先看一下它的继承体系吧:

其实和ServerSocketChannel差不太多,只不过这里直接继承的是AbstractNioByteChannel,而不是AbstractNioMessageChannel,也就是说NioSocketChannel的数据是以byte为单位的,而ServerSocketChannel是以对象为单位的。。。


首先我们来看看AbstractByteChannel的定义吧,主要还是里面的unsafe对象,先来看看read方法:

        public void read() {            assert eventLoop().inEventLoop();            final SelectionKey key = selectionKey();            if (!config().isAutoRead()) {                // only remove readInterestOp if needed                key.interestOps(key.interestOps() & ~readInterestOp);            }//获取当前channel的pipeline            final ChannelPipeline pipeline = pipeline(); //获取当前存数据的buffer,这里是基于字节的buffer            final ByteBuf byteBuf = pipeline.inboundByteBuffer();            boolean closed = false;            boolean read = false;            boolean firedChannelReadSuspended = false;            try {                expandReadBuffer(byteBuf);                loop: for (;;) {                //真正的从channel中读取数据                    int localReadAmount = doReadBytes(byteBuf);                    if (localReadAmount > 0) {                        read = true;                    } else if (localReadAmount < 0) {                        closed = true;                        break;                    }                    switch (expandReadBuffer(byteBuf)) {                    case 0:                        // Read all - stop reading.                        break loop;                    case 1:                        // Keep reading until everything is read.                        break;                    case 2:                        // Let the inbound handler drain the buffer and continue reading.                        if (read) {                            read = false;                            pipeline.fireInboundBufferUpdated();  //这个时候会激活注册的函数,用于处理刚刚读进来的数据                            if (!byteBuf.isWritable()) {                                throw new IllegalStateException(                                        "an inbound handler whose buffer is full must consume at " +                                        "least one byte.");                            }                        }                    }                }            } catch (Throwable t) {                if (read) {                    read = false;                    pipeline.fireInboundBufferUpdated();                }                if (t instanceof IOException) {                    closed = true;                } else if (!closed) {                    firedChannelReadSuspended = true;                    pipeline.fireChannelReadSuspended();                }                pipeline().fireExceptionCaught(t);            } finally {                if (read) {                    pipeline.fireInboundBufferUpdated();                }                if (closed) {                    setInputShutdown();                    if (isOpen()) {                        if (Boolean.TRUE.equals(config().getOption(ChannelOption.ALLOW_HALF_CLOSURE))) {                            key.interestOps(key.interestOps() & ~readInterestOp);                            pipeline.fireUserEventTriggered(ChannelInputShutdownEvent.INSTANCE);                        } else {                            close(voidFuture());                        }                    }                } else if (!firedChannelReadSuspended) {                    pipeline.fireChannelReadSuspended();                }            }        }    }
相对来说还是比较容易读懂的吧,首先获取selectionkey,然后获取当前channel的pipeline,然后再从pipeline里面获取用于存储数据的buffer。

至于真正的读取数据的操作,则是调用doReadBytes方法来完成的,这个方法的实现延后到了在NioSocketChannel中实现。。。最后,读取完了数据之后,会调用fireInboundBufferUpdated方法,来激活注册的函数,用于处理刚刚读进来的数据。。。。

另外就还有发送文件的方法,由于这部分还没有怎么看,所以就先不说了。。。


好了,接下来看看NioSocketChannel吧,其实蛮简单的吧,首先是一个静态类方法,用于创建java nio 的socketchannel,其定义如下:

    //用于创建socketchannel    private static SocketChannel newSocket() {        try {            return SocketChannel.open();  //创建socketchannel,这里就与nio联系了起来,在NioServerSocketChannel中,用的是ServerSocketChannel        } catch (IOException e) {            throw new ChannelException("Failed to open a socket.", e);        }    }
另外就还有一些bind,connect函数,然后还有真正的读取和写数据的定义,先来看从channel里读取数据的函数定义吧:
//真正的读取数据,具体是怎么读的要等到分析了buffer的定义之后才知道了    protected int doReadBytes(ByteBuf byteBuf) throws Exception {        return byteBuf.writeBytes(javaChannel(), byteBuf.writableBytes());    }
因为没有看过buffer部分的代码,所以这一部分也就不知道具体的实现了,其实也都能猜出来,无非是从nio channel里面读取数据,然后保存到buf里面去,这部分就留在以后再分析吧。。。

然后就是用于发送数据的方法定义:

//写数据到channel里面,将buf里面的数据发送出去    protected int doWriteBytes(ByteBuf buf, boolean lastSpin) throws Exception {        final int expectedWrittenBytes = buf.readableBytes();  //相当于是需要发送的数据        final int writtenBytes = buf.readBytes(javaChannel(), expectedWrittenBytes);  //这里就是真正的发送数据        final SelectionKey key = selectionKey();   //获取selectionkey        final int interestOps = key.interestOps();   //获取当前channel挂起的事件        if (writtenBytes >= expectedWrittenBytes) {        //如果想要发送的数据都已经发送完了,那么可以更新感兴趣的事件了,将write事件去除            // Wrote the outbound buffer completely - clear OP_WRITE.            if ((interestOps & SelectionKey.OP_WRITE) != 0) {                key.interestOps(interestOps & ~SelectionKey.OP_WRITE);            }        } else {            // Wrote something or nothing.            // a) If wrote something, the caller will not retry.            //    - Set OP_WRITE so that the event loop calls flushForcibly() later.            // b) If wrote nothing:            //    1) If 'lastSpin' is false, the caller will call this method again real soon.            //       - Do not update OP_WRITE.            //    2) If 'lastSpin' is true, the caller will not retry.            //       - Set OP_WRITE so that the event loop calls flushForcibly() later.        //如果没有发送完数据,那么需要挂起写事件            if (writtenBytes > 0 || lastSpin) {                if ((interestOps & SelectionKey.OP_WRITE) == 0) {                    key.interestOps(interestOps | SelectionKey.OP_WRITE);                }            }        }        return writtenBytes;    }}
其实还是比较容易懂,不过具体是怎么发送的还是需要看buf的代码了,不过猜也能猜出来吧。。又不是很复杂。。。


好了,NioServerSocketChannel一起NioSocketChannel都已经分析的差不多了,那么连接这一块也差不多了。。。那么接下来看什么呢。。。buffer?pipeline?future?

原创粉丝点击