Netty教程—Part4—Server端的执行情况

本文由 ImportNew - 刘海波 翻译自 seeallhearall.blogspot。如需转载本文,请先参见文章末尾处的转载要求。

本文是Netty教程的第四篇。

根据DateSender,我们 只知道服务器端socket是用来监听客服端socket发送的数据。服务器端很像客户端的反面。

服务器socket将承载从客户端接收的byte流的ChannelEvent送到pipeline中的处理器sink中。需要为pipeline配置解码器ObjectDecoder来将byte数组转换为Java对象,在本例中,Java对象是Date类型的。当Date被解码之后会被pipeline中的下一个处理器、自定义的DateHandler处理。你可能会注意到虽然Channels有一个write方 法,却没有相应的read方法。在同步API中 很多这种情况:一个线程需要等待直到数据可用才能从OutputStream(译注:这里应该是InputStream) 读取数据。这也是为什么上面的图表中没有一个指向ServerChannel箭头。同时,pipeline中最后一个处理器使用从客户端发送的所有解码 后的信息做一些有用的操作。

假设服务器端的Channel pipeline是 你真实的业务服务DateReceiver的 调用发起者,pipeline为DataReceiver提供合适的解码数据。当然,你可以创建一个只包含一个处理器的pipeline,使用这个处理器完成所有的操作,但是将多个小模块链接在一起来使用更灵活。例如,如果不仅仅发送一个Date,而是一个拥有300Date的数组,我还想在客户端和服务器的pipeline中添加Compression/Decompression处理器来减少网络传输过程中的负载量,实现这个需求只需要简单的修改pipeline的 配置就行了,而不是在那个无所不能的处理器中添加新代码。或者我想增加一些认证功能防止任何客户端都能给服务器端发送Date、调整Date的时区……模块化的方式更容易实现。

服务器端的DateSender很简单。创建一个Channel工厂、pipeline工 厂,将ObjectDecorder和自定义的DateHandler放到pipeline中。 使用与ClientBootstrap相 应的ServerBootstrap, 不用类似在客户端做的连接操作,然后将ServerBootstrap绑 定到服务器端socket来监听来自于客户端的请求。

public static void bootServer() {
  // More terse code to setup the server
  ServerBootstrap bootstrap = new ServerBootstrap(
    new NioServerSocketChannelFactory(
      Executors.newCachedThreadPool(),
      Executors.newCachedThreadPool()));
  // Set up the pipeline factory.
  bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
   public ChannelPipeline getPipeline() throws Exception {
    return Channels.pipeline(
     new ObjectDecoder(ClassResolvers.cacheDisabled(getClass().getClassLoader())),
     new DateHandler()
    );
   };
  });
  // Bind and start to accept incoming connections.
  bootstrap.bind(new InetSocketAddress("0.0.0.0", 8080));
  slog("Listening on 8080");
 }
 static class DateHandler extends SimpleChannelHandler {
  public void messageReceived(ChannelHandlerContext ctx,MessageEvent e) throws Exception {
   Date date = (Date)e.getMessage();
   // Here's the REALLY important business service at the end of the pipeline
   slog("Hey Guys !  I got a date ! [" + date + "]");
   // Huh ?
   super.messageReceived(ctx, e);
  }  
 }

DateHandler继承了SimpleChannelHandler,这是一种好的方式:当你没有特殊的逻辑需要处理,可以使用定义好的回调。也就是说你不需要监听所有的ChannelEvents、确认是否是你需要的类型。在这种方式下,仅仅需要重 载表示接收数据的messageReceived回 调方法就可以了。

slog和clog是System.out.println的 简单封装,只是输出时的前缀不同:一个是[Server],一个是[Client],可以用来区别不同的输出。

messageReceived简单介绍

之前已经说过,messageReceived是一个当接收到数据时用于回调的方法。这个方法会处理属于ChannelEvent类型的事件:MessageEvent。为了获取MessageEvent中的数据信息,只需要很简单地调用getMessage()方法就能返回一 个java.lang.Object对象,这个对象能被转换为需要的类型数据。注意:如果在这个处理器前面没有转换处理器来转换数据,那么这个数据就是ChannelBuffer类 型的。在这个例子中,ObjectDecorder已经将ChannelBuffer中的数据流转换为java.util.Data类型的日期。至于其他的对象ChannelHandlerContext, 一会就会涉及。

假设业务中关键点就是记录接收 数据的日志,处理器已经从技术上完成了这个要求。那么第30行的代码( super.messageReceived(ctx, e);) 有什么作用呢?因为在pipeline有 可能还有其他的处理器来做进一步的处理,当处理完接收的数据之后总是通过这种方式传送数据是一种很好的方案。如果没有多余的处理 器,pipeline会丢弃这个数据。

如果想了解整个细节,可以去GitHub查 看DateSender的 源码,下面是代码执行的输出:

[Server]:Listening on 8080
[Client]:DateSender Example
[Client]:Issuing Channel Connect...
[Client]:Waiting for Channel Connect...
[Client]:Connected. Sending Date
[Server]:Hey Guys !  I got a date ! [Sat May 19 14:00:58 EDT 2012]

注意这个示例是单向的,只是将日期数据上传导服务器,并没有任何返回。如果 需要返回,在服务器端和客户端的pipeline的都需要相应的处理器, 在后面会讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值