上一篇文章分析了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?