Netty 3.10.1 :通过EchoServer例子研究netty的写机制

通过阅读代码,我们知道当一个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操作。

最后一行比较复杂,比较懒,不分析了。

自定义规则而已,不必较真!

 

 

 

 

 

 

你可能感兴趣的:(netty)