在上一篇文章中分析了AbstractNioChannel,那么在这一篇文章中就分析一个具体的NioChannel类。。。
NioServerSocketChannel类用过netty的应该都比较熟悉吧,如果做服务器端的编程,那么我们一般情况下都是使用的这种类型的channel。
按照惯例,我们还是先来分析一下它的继承体系:
NioServerSocketChannel直接继承自AbstractNioMessageChannel,而AbstractNioMessageChannel则直接继承自AbstractNioChannel,
在这里先分析一下AbstractNioMessageChannel:
@Override
protected AbstractNioUnsafe newUnsafe() {
return new NioMessageUnsafe();
}
这个方法比较重要吧,这里就是真正的创建UnSafe对象了,在AbstractNioMessageChannel中定义了NioMessageUnsafe类型,在其中定义具体的read方法:
public void read() {
assert eventLoop().inEventLoop();
final SelectionKey key = selectionKey(); //获取select key
if (!config().isAutoRead()) {
// only remove readInterestOp if needed
key.interestOps(key.interestOps() & ~readInterestOp);
}
final ChannelPipeline pipeline = pipeline(); //获取pipeline
final MessageBuf<Object> msgBuf = pipeline.inboundMessageBuffer(); //获取存放读取数据的buffer
boolean closed = false;
boolean read = false;
boolean firedChannelReadSuspended = false;
try {
for (;;) {
int localReadAmount = doReadMessages(msgBuf); //其实还是调用doReadMessages方法来读取数据,并将它保存到buffer当中去
if (localReadAmount > 0) {
read = true;
} else if (localReadAmount == 0) {
break;
} else if (localReadAmount < 0) {
closed = true;
break;
}
}
} 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 && isOpen()) {
close(voidFuture());
} else if (!firedChannelReadSuspended) {
pipeline.fireChannelReadSuspended();
}
}
}
}
代码还是比较的简单吧,首先先后去selectkey,然后从pipeline中获取用于存读取数据的buffer,最后再调用doReadMessages方法来真正的读取数据,这个方法在当前的AbstractNioMessageChannel中并没有实现,而是留给了以后具体的类。
@Override
protected void doFlushMessageBuffer(MessageBuf<Object> buf) throws Exception {
final int writeSpinCount = config().getWriteSpinCount() - 1; //总共有多少个buffer需要写
while (!buf.isEmpty()) {
boolean wrote = false;
for (int i = writeSpinCount; i >= 0; i --) {
int localFlushedAmount = doWriteMessages(buf, i == 0); //其实还是调用doWriteMessages方法来发送数据
if (localFlushedAmount > 0) {
wrote = true;
break;
}
}
if (!wrote) {
break;
}
}
}
该方法用于写数据,其实最终也是调用doWriteMessages方法来具体的写数据,而这个方法在当前AbstractNioMessageChannel中也并没有实现,也要等到以后实现。。。
好了,接下来分析NioServerSocketChannel类,首先来看它的构造方法:
public NioServerSocketChannel() {
//在这里,新创建的ServerSocketChannel就是哪个SlectableChannel了
super(null, null, newSocket(), SelectionKey.OP_ACCEPT);
config = new DefaultServerSocketChannelConfig(this, javaChannel().socket());
}
这个应该比较简单吧,调用了newSocket方法来创建具体的channel,这是一个类方法,我们来看看它的定义:
private static ServerSocketChannel newSocket() {
try {
return ServerSocketChannel.open(); //这里就是创建ServerSocketChannel了
} catch (IOException e) {
throw new ChannelException(
"Failed to open a server socket.", e);
}
}
用过java nio的就应该比较熟悉了,这里是创建一个nio 的serversocketchannel对象,也就是在前面AbstractNioChannel中有提到过的SelectableChannel,另外这该类中实现了doReadMessages方法:
@Override
protected int doReadMessages(MessageBuf<Object> buf) throws Exception {
//其实serverchannel的读取,无非就是accept函数啊
SocketChannel ch = javaChannel().accept();
try {
if (ch != null) {
buf.add(new NioSocketChannel(this, null, ch));//将获取的socektchannel放入到buffer当中去
return 1;
}
} 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;
}
很简单吧,其实serverchannel读数据不就是accept方法嘛,至于其他的传输数据的方法,向doConnect,write什么的就直接抛出异常就是了,serverchannel怎么能有这些方法呢。。。
好了,NioServerSocketChannel已经分析的差不多了,接下来该分析什么呢,貌似不知道啊。。。应该是NioSocketChannel,pipeline,promise什么的吧。。。。