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

本文是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的都需要相应的处理器, 在后面会讨论。

原文链接: seeallhearall.blogspot 翻译: ImportNew.com - 刘海波
译文链接: http://www.importnew.com/7686.html
[ 转载请保留原文出处、译者和译文链接。]



相关文章

发表评论

Comment form

(*) 表示必填项

还没有评论。

跳到底部
返回顶部