代码改变世界

Netty基础介绍与框架搭建

2012-12-31 23:08  低调de草原狼  阅读(275)  评论(0编辑  收藏  举报

问题所在:

        目前为止,互联网上的通讯都是通过已有的应用程序或者软件库来实现。例如,我们最常使用的就是利用HTTP协议客户端(浏览器或者其他)从远程服务器上获取信息或者远程web服务。但是,大多数协议都不是为了我们的应用而特殊定制的,就像我们几乎不会用HTTP协议来传输大规模文件,发送电子邮件或是进行实时通讯。我们需要的是一个高度优化的应用框架可以支持我们特殊的需求。例如,你可以搭建一个HTTP server却能同时支持优化的AJAX聊天应用,大型文件传输等等。你甚至可以设计自己的一个网络通讯协议。

 

解决方法:

        Netty是一个高效的、异步的、基于事件驱动的网络通讯框架。使用Netty 可以快速开发出可维护的,高性能、高扩展能力的协议服务及其客户端应用。也就是说,Netty 是一个基于NIO的客户,服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。Netty相当简化和流线化了网络应用的编程开发过程,例如,TCP和UDP的socket服务开发。

       “快速”和“简单”并不意味着会让你的最终应用产生维护性或性能上的问题。Netty是一个吸收了多种协议的实现经验,这些协议包括FTP,SMPT,HTTP,各种二进制,文本协议,并经过相当精心设计的项目,最终,Netty 成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和伸缩性。

       一些用户可能找到了某些同样声称具有这些特性的编程框架,因此你们可能想问Netty又有什么不一样的地方。这个问题的答案是Netty项目的设计哲学。从创立之初,无论是在API还是在其实现上Netty都致力于为你提供最为舒适的使用体验。虽然这并不是显而易见的,但你终将会认识到这种设计哲学将令你在阅读本指南和使用Netty时变得更加得轻松和容易。

客户端与服务器的搭建:
        在详细介绍使用之前,先给出客户端与服务器端基本框架的搭建,以下程序以一个简单的时间服务为例,即客户端向服务器发送连接请求,服务器在收到请求之后就向客户端发送当前系统时间。在后续博客中会介绍每个环节的具体注意事项。废话就不多说了,先上代码:

 

服务器端:

TimeServer.java:

  1. package org.jboss.netty.example.time;  
  2.   
  3. import java.net.InetSocketAddress;  
  4. import java.util.concurrent.Executors;  
  5.   
  6. import org.jboss.netty.bootstrap.ServerBootstrap;  
  7. import org.jboss.netty.channel.Channel;  
  8. import org.jboss.netty.channel.ChannelFactory;  
  9. import org.jboss.netty.channel.ChannelPipeline;  
  10. import org.jboss.netty.channel.ChannelPipelineFactory;  
  11. import org.jboss.netty.channel.Channels;  
  12. import org.jboss.netty.channel.group.ChannelGroup;  
  13. import org.jboss.netty.channel.group.ChannelGroupFuture;  
  14. import org.jboss.netty.channel.group.DefaultChannelGroup;  
  15. import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;  
  16.   
  17. public class TimeServer {  
  18.       
  19.     //DefaultChannelGroup requires the name of the group as a constructor parameter. The group   
  20.     //name is solely used to distinguish one group from others.   
  21.     static final ChannelGroup allChannels = new DefaultChannelGroup("time-server" );  
  22.       
  23.     public static void main(String[] args) throws Exception{  
  24.         ChannelFactory factory = new NioServerSocketChannelFactory(  
  25.                 Executors.newCachedThreadPool(),  
  26.                 Executors.newCachedThreadPool());  
  27.           
  28.         ServerBootstrap bootstrap = new ServerBootstrap(factory);  
  29.         bootstrap.setPipelineFactory(new ChannelPipelineFactory(){  
  30.             public ChannelPipeline getPipeline(){  
  31.                 return Channels.pipeline(  
  32.                         new TimeServerHandler(),  
  33.                         new TimeEncoder()  
  34.                         );  
  35.             }  
  36.         });  
  37.         bootstrap.setOption("child.tcpNoDelay"true);  
  38.         bootstrap.setOption("child.keepAlive"true);  
  39.           
  40.         Channel channel = bootstrap.bind(new InetSocketAddress(8080));  
  41.   
  42.         allChannels.add(channel);  
  43.         waitForShutdownCommand();  
  44.         ChannelGroupFuture future = allChannels.close();  
  45.         future.awaitUninterruptibly();  
  46.         factory.releaseExternalResources();  
  47.     }  
  48. }  


TimeServerHandler.java:

  1. package org.jboss.netty.example.time;  
  2.   
  3. import org.jboss.netty.channel.Channel;  
  4. import org.jboss.netty.channel.ChannelFuture;  
  5. import org.jboss.netty.channel.ChannelFutureListener;  
  6. import org.jboss.netty.channel.ChannelHandlerContext;  
  7. import org.jboss.netty.channel.ChannelStateEvent;  
  8. import org.jboss.netty.channel.ExceptionEvent;  
  9. import org.jboss.netty.channel.SimpleChannelHandler;  
  10.   
  11. public class TimeServerHandler extends SimpleChannelHandler{  
  12. //  @Override   
  13. //  public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e){   
  14. //      Channel ch = e.getChannel();   
  15. //      ChannelBuffer time =  ChannelBuffers.buffer(4);   
  16. //      time.writeInt((int)(System.currentTimeMillis()/1000));   
  17. //         
  18. //      ChannelFuture f = ch.write(time);   
  19. //      f.addListener(new ChannelFutureListener(){   
  20. //          public void operationComplete(ChannelFuture future){   
  21. //              Channel ch = future.getChannel();   
  22. //              ch.close();   
  23. //          }   
  24. //      });   
  25. //  }   
  26.     private static String a = "Hello";  
  27.     public TimeServerHandler(){  
  28.         System.out.println("Hello world " + a);  
  29.     }  
  30.       
  31.     @Override  
  32.     public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {  
  33.         UnixTime time = new UnixTime(System.currentTimeMillis() / 1000);  
  34.         ChannelFuture f = e.getChannel().write(time);  
  35.         f.addListener(ChannelFutureListener.CLOSE);  
  36.     }  
  37.       
  38.     @Override  
  39.     public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) {  
  40.         TimeServer.allChannels.add(e.getChannel());  
  41.     }  
  42.       
  43.     @Override  
  44.     public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e){  
  45.         e.getCause().printStackTrace();  
  46.           
  47.         Channel ch = e.getChannel();  
  48.         ch.close();  
  49.     }  
  50. }  

 

TimeEncoder.java:

  1. package org.jboss.netty.example.time;  
  2.   
  3.   
  4. import static org.jboss.netty.buffer.ChannelBuffers.buffer;  
  5.   
  6. import org.jboss.netty.buffer.ChannelBuffer;  
  7. import org.jboss.netty.channel.ChannelHandlerContext;  
  8. import org.jboss.netty.channel.Channels;  
  9. import org.jboss.netty.channel.MessageEvent;  
  10. import org.jboss.netty.channel.SimpleChannelHandler;  
  11.   
  12. public class TimeEncoder extends SimpleChannelHandler{  
  13.     @Override  
  14.     public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) {  
  15.         UnixTime time = (UnixTime) e.getMessage();  
  16.         ChannelBuffer buf = buffer(4);  
  17.         buf.writeInt((int)time.getValue());  
  18.         Channels.write(ctx, e.getFuture(), buf);  
  19.     }  
  20. }  


客户端代码:

TimeClient.java:

  1. package org.jboss.netty.example.time;  
  2.   
  3. import java.net.InetSocketAddress;  
  4. import java.util.concurrent.Executors;  
  5.   
  6. import org.jboss.netty.bootstrap.ClientBootstrap;  
  7. import org.jboss.netty.channel.ChannelFactory;  
  8. import org.jboss.netty.channel.ChannelFuture;  
  9. import org.jboss.netty.channel.ChannelPipeline;  
  10. import org.jboss.netty.channel.ChannelPipelineFactory;  
  11. import org.jboss.netty.channel.Channels;  
  12. import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;  
  13.   
  14.   
  15. public class TimeClient {  
  16.     public static void main(String[] args) throws Exception{  
  17.         String host = args[0];  
  18.         int port = Integer.parseInt(args[1]);  
  19. //      String host = "localhost";   
  20. //      int port = 8080;           
  21.         ChannelFactory factory = new NioClientSocketChannelFactory(  
  22.                 Executors.newCachedThreadPool(),  
  23.                 Executors.newCachedThreadPool());  
  24.           
  25.         ClientBootstrap bootstrap = new  ClientBootstrap(factory);  
  26.           
  27.         bootstrap.setPipelineFactory(new ChannelPipelineFactory() {  
  28.             public ChannelPipeline getPipeline(){  
  29.                 return Channels.pipeline(  
  30.                         new TimeDecoder(),  
  31.                         new TimeClientHandler());  
  32.             }  
  33.         });  
  34.           
  35.         bootstrap.setOption("tcpNoDelay"true);  
  36.         bootstrap.setOption("keepAlive"true);  
  37.           
  38.         ChannelFuture future = bootstrap.connect(new InetSocketAddress(host,port));  
  39.         future.awaitUninterruptibly();  
  40.         if (!future.isSuccess()) {  
  41.             future.getCause().printStackTrace();  
  42.         }  
  43.         future.getChannel().getCloseFuture().awaitUninterruptibly();  
  44.         factory.releaseExternalResources();  
  45.     }  
  46. }  


TimeDecoder.java:

  1. package org.jboss.netty.example.time;  
  2.   
  3. import org.jboss.netty.buffer.ChannelBuffer;  
  4. import org.jboss.netty.channel.Channel;  
  5. import org.jboss.netty.channel.ChannelHandlerContext;  
  6. import org.jboss.netty.handler.codec.frame.FrameDecoder;  
  7.   
  8. public class TimeDecoder extends FrameDecoder{  
  9. //  @Override   
  10. //  protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer){   
  11. //      if(buffer.readableBytes() < 4){   
  12. //          return null;   
  13. //      }   
  14. //      return buffer.readBytes(4);   
  15. //  }   
  16.       
  17.     @Override  
  18.     protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer){  
  19.         if(buffer.readableBytes() < 4){  
  20.             return null;  
  21.         }  
  22.           
  23.         return new UnixTime(buffer.readInt());  
  24.     }  
  25. }  

 

TimeClientHandler.java:

  1. package org.jboss.netty.example.time;  
  2.   
  3. import java.util.Date;  
  4.   
  5. import org.jboss.netty.buffer.ChannelBuffer;  
  6. import org.jboss.netty.channel.ChannelHandlerContext;  
  7. import org.jboss.netty.channel.MessageEvent;  
  8. import org.jboss.netty.channel.SimpleChannelHandler;  
  9.   
  10. public class TimeClientHandler extends SimpleChannelHandler{  
  11. //  @Override   
  12. //  public void messageReceived(ChannelHandlerContext ctx, MessageEvent e){   
  13. //      ChannelBuffer buf = (ChannelBuffer)e.getMessage();   
  14. //      long currentTimeMillis = buf.readInt() * 1000L;   
  15. //      System.out.println(new Date(currentTimeMillis));   
  16. //      e.getChannel().close();   
  17. //  }   
  18.       
  19.     @Override  
  20.     public void messageReceived(ChannelHandlerContext ctx, MessageEvent e){  
  21.         UnixTime m = (UnixTime)e.getMessage();  
  22.         System.out.println(m);  
  23.         e.getChannel().close();  
  24.     }  
  25. }  


共用数据结构:

UnixTime.java:

  1. package org.jboss.netty.example.time;  
  2.   
  3. import java.util.Date;  
  4.   
  5. public class UnixTime {  
  6.     private final long value;  
  7.     public UnixTime(long value){  
  8.         this.value = value;  
  9.     }  
  10.       
  11.     public long getValue(){  
  12.         return value;  
  13.     }  
  14.       
  15.     @Override  
  16.     public String toString(){  
  17.         return new Date(value * 1000L).toString();  
  18.     }  
  19.   
  20. }