`
潜心修炼
  • 浏览: 18688 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Netty的服务器实现浅析

阅读更多
    如果你现在还在写着操作socket的代码,也许不能说你落伍,但至少也不能说你做的工作很超前。因为现在有很多的网络通信框架已经把底层的东东封装的很完善,今天要说的Netty也算是一款不错的产品了。
    突然半路进来看Netty其实是最近看HornetQ的缘故,HornetQ的底层传输的实现就是借助了Netty。按照官方的解释,Netty是一个异步的事件驱动的网络应用框架,它使得我们关于客户端服务器协议的开发变得更加的方便,维护更容易,扩展性更好。它极大的简化了我们的网络编程。更为难得的是Netty顺便打包了一堆很好的例子,对于快速入门的人来说能够很短的时间内就对其有了感官上的认识。我们就从一个例子开始吧。

package org.jboss.netty.example.discard;

import java.net.InetSocketAddress;
import java.util.concurrent.Executors;

import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory;

public class DiscardServer {

    public static void main(String[] args) throws Exception {
        // Configure the server.
        ServerBootstrap bootstrap = new ServerBootstrap(
                new OioServerSocketChannelFactory(
                        Executors.newCachedThreadPool(),
                        Executors.newCachedThreadPool()));

        // Set up the pipeline factory.
        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            public ChannelPipeline getPipeline() throws Exception {
                return Channels.pipeline(new DiscardServerHandler());
            }
        });

        // Bind and start to accept incoming connections.
        bootstrap.bind(new InetSocketAddress(8080));
    }
}
 

    上面的程序主要是用来启动了一个服务器端的服务,这个服务会监听本机的8080端口,也就是说你可以通过客户端来访问8080端口了。 ServerBootstrap 类作为一个工具类,用来启动服务器程序。这段程序主要就是做了三件事:

  • 设置ChannelFactory,也就是要设置服务器通信的方式,例子就是借助socket的通信,当然你也可以设置成基于nio形式或者数据报形式的。
  • 设置PipelineFactory,其实是为了设置一组Handler,这组Handler会对这个通信的过程进行处理,比如说解码,然后业务处理,然后编码数据。
  • bootstrap.bind(new InetSocketAddress(8080)); 就是来启动服务。很多猫腻就是出现在这。


介绍完上面的例子,我们来说Netty代码中几个关键类型的类。

Channel
Channel是Netty中数据流转的通道,它对底层的数据传输比如socket等进行了封装,我们可以借助于Channel来完成数据的读写,通道的打开和关闭等操作。Channel可以分为服务器的Channel和于客户端进行通信的Channel。


ChannelEvent
定义了一系列的事件类型,比如说Conenct,Receive,Write的等等。这符合Command模式,肯定会有某个地方来对这些命令做不同的处理

ChannelHandler可以看成是Interceptor,也就是说ChannelHandler会针对发生在Channel中的一些事件进行特定的动作处理。ChannelHandler可以分成ChannelUpstreamHandler和ChannelDownstreamHandler两种 ,顾名思义,就是说这两种handler会对不同流向的事件发挥作用。

ChannelPipeline Netty是基于事件驱动的,归根结底就是通过ChannelPipeline来控制事件流。我们通过在ChannelPipeline上注册一系列ChannelHandler来处理事件。ChannelPipeline内部维护了一个ChannelHandlerContext的集合,每个ChannelHandlerContext都会维护前后是那个ChannelHandlerContext,类似一个双向的链表。上面说到ChannelHandler分为Up和Down两个方向,那么如何理解Up和Down?其实,Up就是说流入的事件,Down就是流出的事件。对于客户端,读到客户端程序写入的数据就是流入,而返回数据也就是将数据写回到客户端就属于流出的事件。发生流入的事件时,只有属于ChannelUpstreamHandler才有资格处理。而对于流出的时间,则ChannelDownstreamHandler才有资格处理。对于一个ChannelPipeline上注册的多个Handler,他们注册的顺序决定了他们处理的顺序。那么对于流出的事件来说,所有的handler都处理完毕之后,需要有一个类真正的服务将数据写回到客户端,这个类就是下面所说的ChannelSink.

ChannelSinkchannelPipline完成所有的DownHandler后通过 ChannelSink来进行底层通信的处理。

XIOWorker 负责与底层通信,如数据的写入输出。X根据协议的不同而不同。


下面说一下Netty中服务器端的工作原理,本图引自边城客栈http://www.kafka0102.com,如果图的作者对于本文中的引用有意见可以给我留言,我会删除此图。




    如图所示,服务器端通过mainReactor来处理客户端的连接请求(ChannelSink的Boss内部类充当的就是mainReactor的角色),每建立一个连接后,就会从连接池中获取或者新建一个subReactor(XIOWorker,X根据协议的不同而不同)来专门处理与某个客户端的通信工作。

类图:



不知不觉已经十二点多了,就此打住了。欢迎朋友们多多交流。

  • 大小: 90 KB
  • 大小: 36.1 KB
2
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics