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