Netty 3.x 简例

Netty是一个异步的、事件驱动的网络应用框架,可以用来快速开发高性的客户端、服务端程序。示例使用Netty 3.10.5

首先是Server部分的代码:

Server端主程序:

  1. package com.sean.server;  
  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.group.ChannelGroup;  
  10. import org.jboss.netty.channel.group.ChannelGroupFuture;  
  11. import org.jboss.netty.channel.group.DefaultChannelGroup;  
  12. import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;  
  13.   
  14. public class Server {  
  15.     private ChannelFactory factory;  
  16.       
  17.     public static ChannelGroup channelGroup = new DefaultChannelGroup();  
  18.       
  19.     public void start(){  
  20.         // NioServerSocketChannelFactory用于创建基于NIO的服务端  
  21.         // ServerSocketChannel。本身包含2种线程,boss线程和worker线程。  
  22.         // 每个ServerSocketChannel会都会拥有自己的boss线程,  
  23.         // 当一个连接被服务端接受(accepted),  
  24.         // boss线程就会将接收到的Channel传递给一个worker线程处理,  
  25.         // 而worker线程以非阻塞的方式为一个或多个Channel提供非阻塞的读写  
  26.         factory = new NioServerSocketChannelFactory(  
  27.                 Executors.newCachedThreadPool(),    // boss线程池  
  28.                 Executors.newCachedThreadPool(),    // worker线程池  
  29.                 8); // worker线程数  
  30.           
  31.         // ServerBootstrap用于帮助服务器启动  
  32.         ServerBootstrap bootstrap = new ServerBootstrap(factory);  
  33.           
  34.         // 没有child.前缀,则该选项是为ServerSocketChannel设置  
  35.         bootstrap.setOption("reuseAddress"true);  
  36.         // 有child.前缀,则该选项是为Channel设置  
  37. //      bootstrap.setOption("child.tcpNoDelay", true);  
  38. //      bootstrap.setOption("child.keepAlive", true);  
  39.       
  40.         // 对每一个连接(channel),server都会调用  
  41.         // ChannelPipelineFactory为该连接创建一个ChannelPipeline  
  42.         ServerChannelPiplineFactory channelPiplineFactory =  
  43.                 new ServerChannelPiplineFactory();  
  44.         bootstrap.setPipelineFactory(channelPiplineFactory);  
  45.           
  46.         // 这里绑定服务端监听的IP和端口  
  47.         Channel channel = bootstrap.bind(new InetSocketAddress("127.0.0.1"8000));  
  48.         Server.channelGroup.add(channel);  
  49.           
  50.         System.out.println("Server is started...");  
  51.     }  
  52.       
  53.     public void stop(){  
  54.         // ChannelGroup为其管理的Channels提供一系列的批量操作  
  55.         // 关闭的Channel会自动从ChannelGroup中移除  
  56.         ChannelGroupFuture channelGroupFuture = Server.channelGroup.close();  
  57.         channelGroupFuture.awaitUninterruptibly();  
  58.         factory.releaseExternalResources();  
  59.         System.out.println("Server is stopped.");  
  60.     }  
  61.   
  62.     public static void main(String[] args) throws Exception {  
  63.         Server server = new Server();  
  64.         server.start();  
  65.         Thread.sleep(30*1000);  
  66.         server.stop();  
  67.     }  
  68. }  

PipelineFactory:

  1. package com.sean.server;  
  2.   
  3. import java.util.concurrent.Executor;  
  4.   
  5. import org.jboss.netty.channel.ChannelPipeline;  
  6. import org.jboss.netty.channel.ChannelPipelineFactory;  
  7. import org.jboss.netty.channel.Channels;  
  8. import org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor;  
  9.   
  10. import com.sean.server.handler.ServerExecutionHandler;  
  11. import com.sean.server.handler.ServerLogicHandler;  
  12. import com.sean.server.handler.ServerReadDecoder;  
  13. import com.sean.server.handler.ServerWriteEncoder;  
  14.   
  15. public class ServerChannelPiplineFactory implements ChannelPipelineFactory {  
  16.   
  17.     @Override  
  18.     public ChannelPipeline getPipeline() throws Exception {  
  19.         ServerReadDecoder serverReadDecoder = new ServerReadDecoder();  
  20.         ServerWriteEncoder serverWriteEncoder = new ServerWriteEncoder();  
  21.         Executor executor =   
  22.                 new OrderedMemoryAwareThreadPoolExecutor(4200200);  
  23.         ServerExecutionHandler serverExecutionHandler =   
  24.                 new ServerExecutionHandler(executor);  
  25.         ServerLogicHandler serverLogicHandler = new ServerLogicHandler();  
  26.           
  27.         // ChannelPipeline的源码中的javadoc介绍的非常详细,很有必要看一下  
  28.         // ChannelPipeline是一个处理ChannelEvent的handler链  
  29.         // 如果为读操作,ChannelEvent事件会从前到后依次被  
  30.         // Upstream的handler处理  
  31.         // serverReadDecoder -> serverLogicHandler  
  32.         // 如果为写操作,ChannelEvent事件会从后至前依次被  
  33.         // Downstream的handler处理  
  34.         // serverLogicHandler -> serverWriteEncoder  
  35.         ChannelPipeline channelPipeline = Channels.pipeline();  
  36.         channelPipeline.addLast("1", serverReadDecoder);  
  37.         channelPipeline.addLast("2", serverWriteEncoder);  
  38.         channelPipeline.addLast("3", serverExecutionHandler);  
  39.         channelPipeline.addLast("4", serverLogicHandler);  
  40.           
  41.         System.out.println(channelPipeline.hashCode());  
  42.         return channelPipeline;  
  43.     }  
  44.   
  45. }  

各个Handler:

  1. package com.sean.server.handler;  
  2.   
  3. import java.util.concurrent.Executor;  
  4.   
  5. import org.jboss.netty.handler.execution.ExecutionHandler;  
  6.   
  7. // 提供一个线程池  
  8. public class ServerExecutionHandler extends ExecutionHandler{  
  9.   
  10.     public ServerExecutionHandler(Executor executor) {  
  11.         super(executor);  
  12.     }  
  13. }  
  1. package com.sean.server.handler;  
  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.MessageEvent;  
  10. import org.jboss.netty.channel.SimpleChannelHandler;  
  11.   
  12. import com.sean.server.Server;  
  13.   
  14. // SimpleChannelHandler提供了很多基本的handler方法用来重写  
  15. // 通常情况下足够使用了  
  16. public class ServerLogicHandler extends SimpleChannelHandler {  
  17.     @Override  
  18.     public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)  
  19.             throws Exception {  
  20.         System.out.println("######channelConnected");  
  21.         // channel group is thread safe  
  22.         Server.channelGroup.add(e.getChannel());  
  23.         System.out.println(e.getChannel().toString());  
  24.     }  
  25.   
  26.     @Override  
  27.     public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {  
  28.         System.out.println("######messageReceived");  
  29.           
  30.         // 经过了ServerReadDecoder的处理,这里可以直接得到String类型的message  
  31.         String msg = (String)e.getMessage();  
  32.         System.out.println("The message sent by client is : " + msg);  
  33.           
  34.         Channel ch = e.getChannel();  
  35.         String str = "Hi, Client.";  
  36.         // 由于IO操作是异步的,当方法返回时并不能保证IO操作一定完成了  
  37.         // 因此返回一个ChannelFuture对象实例  
  38.         // 该实例中保存了IO操作的状态信息  
  39.         ChannelFuture cf = ch.write(str);  
  40.         // 为ChannelFuture对象实例添加监听,如果数据发送完毕则关闭连接  
  41.         cf.addListener(new ChannelFutureListener(){  
  42.             @Override  
  43.             public void operationComplete(ChannelFuture future)  
  44.                     throws Exception {  
  45.                 Channel ch = future.getChannel();  
  46.                 ch.close();  
  47.             }  
  48.         });  
  49.           
  50.         System.out.println("The message has sent to client.");  
  51.     }  
  52.    
  53.     @Override  
  54.     public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {  
  55.         e.getCause().printStackTrace();  
  56.         Channel ch = e.getChannel();  
  57.         ch.close();  
  58.     }  
  59. }  
  1. package com.sean.server.handler;  
  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.string.StringDecoder;  
  7. import org.jboss.netty.util.CharsetUtil;  
  8.   
  9. // 解决接收流数据时,数据出现碎片化的问题  
  10. public class ServerReadDecoder extends StringDecoder{  
  11.   
  12.     @Override  
  13.     protected Object decode(ChannelHandlerContext ctx, Channel channel,  
  14.             Object msg) throws Exception {  
  15.         System.out.println("######ServerReadDecoder");  
  16.           
  17.         // 从msg中取出的数据类型是ChannelBuffer的  
  18.         byte[] buffer = ((ChannelBuffer)msg).array();  
  19.         byte last = buffer[buffer.length - 1];  
  20.         // 46 is '.'  
  21.         if(last == 46)  
  22.             // 并将ChannelBuffer转为String  
  23.             return new String(buffer, CharsetUtil.UTF_8);  
  24.         return null;  
  25.     }  
  26. }  
  1. package com.sean.server.handler;  
  2.   
  3. import org.jboss.netty.buffer.ChannelBuffer;  
  4. import org.jboss.netty.buffer.ChannelBuffers;  
  5. import org.jboss.netty.channel.Channel;  
  6. import org.jboss.netty.channel.ChannelHandlerContext;  
  7. import org.jboss.netty.handler.codec.string.StringEncoder;  
  8. import org.jboss.netty.util.CharsetUtil;  
  9.   
  10. public class ServerWriteEncoder extends StringEncoder{  
  11.   
  12.     @Override  
  13.     protected Object encode(ChannelHandlerContext ctx, Channel channel,  
  14.             Object msg) throws Exception {  
  15.         System.out.println("######ServerWriteEncoder");  
  16.           
  17.         String str = (String)msg;  
  18.         // 通过ChannelBuffers工具,为指定编码的指定字符串分配缓存空间  
  19.         // 并将String转为ChannelBuffer  
  20.         ChannelBuffer channelBuffer =   
  21.                 ChannelBuffers.copiedBuffer(str, CharsetUtil.UTF_8);  
  22.         return channelBuffer;  
  23.     }  
  24. }  

然后是Client部分的代码:

Client端主程序:

  1. package com.sean.client;  
  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.ChannelPipeline;  
  9. import org.jboss.netty.channel.ChannelPipelineFactory;  
  10. import org.jboss.netty.channel.Channels;  
  11. import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;  
  12.   
  13. import com.sean.client.handler.ClientLogicHandler;  
  14. import com.sean.client.handler.ClientReadDecoder;  
  15. import com.sean.client.handler.ClientWriteEncoder;  
  16.   
  17. public class Client {  
  18.     public static void main(String[] args){  
  19.         // 同服务端相同,只是这里使用的是NioClientSocketChannelFactory  
  20.         final ChannelFactory factory = new NioClientSocketChannelFactory(  
  21.                 Executors.newCachedThreadPool(),      
  22.                 Executors.newCachedThreadPool(),      
  23.                 8);   
  24.           
  25.         // ClientBootstrap用于帮助客户端启动  
  26.         ClientBootstrap bootstrap = new ClientBootstrap(factory);  
  27.         // 由于客户端不包含ServerSocketChannel,所以参数名不能带有child.前缀  
  28.         bootstrap.setOption("tcpNoDelay"true);  
  29. //      bootstrap.setOption("keepAlive", true);  
  30.       
  31.         bootstrap.setPipelineFactory(new ChannelPipelineFactory(){  
  32.             @Override  
  33.             public ChannelPipeline getPipeline() throws Exception {  
  34.                 ChannelPipeline channelPipeline =  
  35.                         Channels.pipeline(new ClientReadDecoder(),   
  36.                         new ClientWriteEncoder(), new ClientLogicHandler());  
  37.                   
  38.                 System.out.println(channelPipeline.hashCode());  
  39.                 return channelPipeline;  
  40.             }  
  41.         });  
  42.           
  43.         // 这里连接服务端绑定的IP和端口  
  44.         bootstrap.connect(new InetSocketAddress("127.0.0.1"8000));  
  45.         System.out.println("Client is started...");  
  46.     }  
  47. }  

各个Handler:

  1. package com.sean.client.handler;  
  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.MessageEvent;  
  10. import org.jboss.netty.channel.SimpleChannelHandler;  
  11. import org.jboss.netty.channel.WriteCompletionEvent;  
  12.   
  13. public class ClientLogicHandler extends SimpleChannelHandler {  
  14.       
  15.     @Override  
  16.     public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)  
  17.             throws Exception {  
  18.         System.out.println("######channelConnected");  
  19.           
  20.         Channel ch = e.getChannel();  
  21.         String msg = "Hi, Server.";  
  22.         ch.write(msg);  
  23.     }  
  24.   
  25.     @Override  
  26.     public void writeComplete(ChannelHandlerContext ctx, WriteCompletionEvent e)  
  27.             throws Exception {  
  28.         System.out.println("######writeComplete");  
  29.     }  
  30.   
  31.     @Override  
  32.     public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {  
  33.         System.out.println("######messageReceived");  
  34.           
  35.         String msg = (String)e.getMessage();  
  36.         System.out.println("The message gotten from server is : " + msg);  
  37.           
  38.         ChannelFuture channelFuture = e.getChannel().close();  
  39.         channelFuture.addListener(ChannelFutureListener.CLOSE);  
  40.     }  
  41.   
  42.     @Override  
  43.     public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {  
  44.         e.getCause().printStackTrace();  
  45.         Channel ch = e.getChannel();  
  46.         ch.close();  
  47.     }  
  48. }  
  1. package com.sean.client.handler;  
  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.string.StringDecoder;  
  7. import org.jboss.netty.util.CharsetUtil;  
  8.   
  9. public class ClientReadDecoder extends StringDecoder{  
  10.   
  11.     @Override  
  12.     protected Object decode(ChannelHandlerContext ctx, Channel channel,  
  13.             Object msg) throws Exception {  
  14.         System.out.println("######ClientReadDecoder");  
  15.           
  16.         byte[] buffer = ((ChannelBuffer)msg).array();  
  17.         byte last = buffer[buffer.length - 1];  
  18.         // 46 is '.'  
  19.         if(last == 46)  
  20.             return new String(buffer, CharsetUtil.UTF_8);  
  21.         return null;  
  22.     }  
  23. }  
  1. package com.sean.client.handler;  
  2.   
  3. import org.jboss.netty.buffer.ChannelBuffer;  
  4. import org.jboss.netty.buffer.ChannelBuffers;  
  5. import org.jboss.netty.channel.Channel;  
  6. import org.jboss.netty.channel.ChannelHandlerContext;  
  7. import org.jboss.netty.handler.codec.string.StringEncoder;  
  8. import org.jboss.netty.util.CharsetUtil;  
  9.   
  10. public class ClientWriteEncoder extends StringEncoder{  
  11.   
  12.     @Override  
  13.     protected Object encode(ChannelHandlerContext ctx, Channel channel,  
  14.             Object msg) throws Exception {  
  15.         System.out.println("######ClientWriteEncoder");  
  16.           
  17.         String str = (String)msg;  
  18.         ChannelBuffer channelBuffer =   
  19.                 ChannelBuffers.copiedBuffer(str, CharsetUtil.UTF_8);  
  20.         return channelBuffer;  
  21.     }  
  22. }  

运行结果如下:

Server端后台日志:

  1. Server is started...  
  2. 1257526899  
  3. ######channelConnected  
  4. [id: 0x88120865, /127.0.0.1:58887 => /127.0.0.1:8000]  
  5. ######ServerReadDecoder  
  6. ######messageReceived  
  7. The message sent by client is : Hi, Server.  
  8. ######ServerWriteEncoder  
  9. The message has sent to client.  
  10. Server is stopped.  

Client端后台日志:

  1. 1767582956  
  2. Client is started...  
  3. ######channelConnected  
  4. ######ClientWriteEncoder  
  5. ######writeComplete  
  6. ######ClientReadDecoder  
  7. ######messageReceived  
  8. The message gotten from server is : Hi, Client. 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值