java netty之NioSocketChannel

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

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

java netty之NioSocketChannel_第1张图片

其实和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?

你可能感兴趣的:(java netty之NioSocketChannel)