通过阅读代码,我们知道当一个NioServerSocketChannel可读时,NioWorker会读取信息,
然后调用NioServerSocketChannel对应的PipeLine进行消息传递,
从而触发我们自定义的ChannelHandler的
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
操作,这部分其实没什么好说的,但是这里面的消息是如何写到NioServerSocketChannel里呢?
下面就通过jdb来跟踪代码研究下整个过程。
---------------------------------------------------------------------------------------------------
jdb org.jboss.netty.example.echo.EchoServer
stop in org.jboss.netty.example.echo.EchoServerHandler.messageReceived
run
---------------------------------------------------------------------------------------------------
messageReceived的代码如下:
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
// Send back the received message to the remote peer.
transferredBytes.addAndGet(((ChannelBuffer) e.getMessage()).readableBytes());
e.getChannel().write(e.getMessage());
}
第一行只是做一个统计,按下不表,重点是第2行。
这里的e.getMessage()是一个类型为:New I/O worker #1[1] print message
message = "BigEndianHeapChannelBuffer(ridx=0, widx=256, cap=256)"类似的对象。
---调用的是
return Channels.write(this, message); 也就是调用了一个静态方法。
我们去分析这个静态方法。
----------------------------------------------------------------------
方法继续调用
public static ChannelFuture write(Channel channel, Object message) {
return write(channel, message, null);
}
---继续调用
public static ChannelFuture write(Channel channel, Object message, SocketAddress remoteAddress) {
ChannelFuture future = future(channel);
channel.getPipeline().sendDownstream(
new DownstreamMessageEvent(channel, future, message, remoteAddress));
return future;
}
这里先产生了一个future.再调用pipeline来处理一个DownstreamMessageEvent事件。
由于在echo的例子中,pipiline里的message处理器只能处理上行消息,无法处理下行,
所以最后调用
Step completed: New I/O worker #1[1] "thread=New I/O worker #1", org.jboss.netty.channel.DefaultChannelPipeline.sendDownstream(), line=574 bci=13
574 getSink().eventSunk(this, e);
来发送到sink里。
--------------
继续跟踪此事件
其中sink的类型为
New I/O worker #1[1] print sink
sink = "org.jboss.netty.channel.socket.nio.NioServerSocketPipelineSink@11c34fb"
---
具体的eventSunk的代码为
public void eventSunk(
ChannelPipeline pipeline, ChannelEvent e) throws Exception {
Channel channel = e.getChannel();
if (channel instanceof NioServerSocketChannel) {
handleServerSocket(e);
} else if (channel instanceof NioSocketChannel) {
handleAcceptedSocket(e);
}
}
这里自然是下一个的 else if 分支,所以执行handleAcceptedSocket(e);
代码如下:
private static void handleAcceptedSocket(ChannelEvent e) {
if (e instanceof ChannelStateEvent) {
ChannelStateEvent event = (ChannelStateEvent) e;
NioSocketChannel channel = (NioSocketChannel) event.getChannel();
ChannelFuture future = event.getFuture();
ChannelState state = event.getState();
Object value = event.getValue();
switch (state) {
case OPEN:
if (Boolean.FALSE.equals(value)) {
channel.worker.close(channel, future);
}
break;
case BOUND:
case CONNECTED:
if (value == null) {
channel.worker.close(channel, future);
}
break;
case INTEREST_OPS:
channel.worker.setInterestOps(channel, future, ((Integer) value).intValue());
break;
}
} else if (e instanceof MessageEvent) {//从这里执行
MessageEvent event = (MessageEvent) e;
NioSocketChannel channel = (NioSocketChannel) event.getChannel();
boolean offered = channel.writeBufferQueue.offer(event);
assert offered;
channel.worker.writeFromUserCode(channel);
}
走的分支是: } else if (e instanceof MessageEvent)
具体的操作这里就很简单了。
第1行是取得消息
第2行是取得对应的SocketChannel对象
第3行是放到对应的写缓冲队列里。
到此我们的目的也就达到了,确实是一个异步IO操作。
最后一行比较复杂,比较懒,不分析了。
自定义规则而已,不必较真!