netty初析

来源:互联网 发布:网络性能监控软件 编辑:程序博客网 时间:2024/06/11 21:14

Netty是什么?
本质:JBoss做的一个Jar包
目的:快速开发高性能、高可靠性的网络服务器和客户端程序
优点:提供异步的、事件驱动的网络应用程序框架和工具

通俗的说:一个好使的处理Socket的东东

如果没有Netty?
远古:java.net + java.io
近代:java.nio
其他:Mina,Grizzly

为什么不是Mina?
1、都是Trustin Lee的作品,Netty更晚;
2、Mina将内核和一些特性的联系过于紧密,使得用户在不需要这些特性的时候无法脱离,相比下性能会有所下降,Netty解决了这个设计问题;
3、Netty的文档更清晰,很多Mina的特性在Netty里都有;
4、Netty更新周期更短,新版本的发布比较快;
5、它们的架构差别不大,Mina靠apache生存,而Netty靠jboss,和jboss的结合度非常高,Netty有对google protocal buf的支持,有更完整的ioc容器支持(spring,guice,jbossmc和osgi);
6、Netty比Mina使用起来更简单,Netty里你可以自定义的处理upstream events 或/和 downstream events,可以使用decoder和encoder来解码和编码发送内容;
7、Netty和Mina在处理UDP时有一些不同,Netty将UDP无连接的特性暴露出来;而Mina对UDP进行了高级层次的抽象,可以把UDP当成”面向连接”的协议,而要Netty做到这一点比较困难。

Netty的特性
1. 设计
统一的API,适用于不同的协议(阻塞和非阻塞)
基于灵活、可扩展的事件驱动模型
高度可定制的线程模型
可靠的无连接数据Socket支持(UDP)
2. 性能
更好的吞吐量,低延迟
更省资源
尽量减少不必要的内存拷贝
3. 安全
完整的SSL/TLS和STARTTLS的支持
能在Applet与Android的限制环境运行良好
4. 健壮性
不再因过快、过慢或超负载连接导致OutOfMemoryError
不再有在高速网络环境下NIO读写频率不一致的问题
5. 易用
完善的JavaDoc,用户指南和样例
简洁简单
仅信赖于JDK1.5

Netty包的整体流程
NioServerSocketChannelFactory创建服务端的ServerSocketChannel,采用多线程执行非阻塞IO,和Mina的设计模式一样,都采用了Reactor模式。其中bossExecutor、workerExecutor是两个线程池,bossExecutor用来接收客户端连接,workerExecutor用来执行非阻塞的IO操作,主要是read,write。
这里写图片描述
这里写图片描述

下面举例一个简单的Netty服务实现

netty的模式其实就是reactor模式,如下表示reactor模式
这里写图片描述

服务端

package com.roger.java.pattrn.reactor;import java.net.InetSocketAddress;import java.util.concurrent.Executors;import org.jboss.netty.bootstrap.ServerBootstrap;import org.jboss.netty.channel.Channel;import org.jboss.netty.channel.ChannelFactory;import org.jboss.netty.channel.ChannelPipeline;import org.jboss.netty.channel.ChannelPipelineFactory;import org.jboss.netty.channel.Channels;import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;import org.jboss.netty.handler.codec.string.StringDecoder;import org.jboss.netty.handler.codec.string.StringEncoder;public class DiscardServer {    public static void main(String[] args) throws Exception {          ChannelFactory factory = new NioServerSocketChannelFactory(              Executors.newCachedThreadPool(),              Executors.newCachedThreadPool());          ServerBootstrap bootstrap = new ServerBootstrap (factory);          bootstrap.setPipelineFactory(new ChannelPipelineFactory() {              public ChannelPipeline getPipeline() {                  ChannelPipeline pipeline = Channels.pipeline();                  pipeline.addLast("encode",new StringEncoder());                  pipeline.addLast("decode",new StringDecoder());                  pipeline.addLast("handler",new DiscardServerHandler());                  //pipeline.addLast("handler",new DiscardServerHandler2());                return pipeline;              }          });          bootstrap.setOption("child.tcpNoDelay", true);          bootstrap.setOption("child.keepAlive", true);          Channel bind = bootstrap.bind(new InetSocketAddress(8080));          System.out.println("Server已经启动,监听端口: " + bind.getLocalAddress() + ", 等待客户端注册。。。");      }  }

Handler

package com.roger.java.pattrn.reactor;import org.jboss.netty.channel.Channel;import org.jboss.netty.channel.ChannelHandlerContext;import org.jboss.netty.channel.ChannelStateEvent;import org.jboss.netty.channel.ExceptionEvent;import org.jboss.netty.channel.MessageEvent;import org.jboss.netty.channel.SimpleChannelHandler;public class DiscardServerHandler  extends SimpleChannelHandler {    @Override      public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)  throws Exception {           if (e.getMessage() instanceof String) {               String message = (String) e.getMessage();               System.out.println("Client发来:" + message);               e.getChannel().write("Server已收到刚发送的:" + message);               System.out.println("\n等待客户端输入。。。");           }           super.messageReceived(ctx, e);    }     @Override      public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {          System.out.println("有一个客户端注册上来了。。。");          System.out.println("Client:" + e.getChannel().getRemoteAddress());          System.out.println("Server:" + e.getChannel().getLocalAddress());          System.out.println("\n等待客户端输入。。。");          super.channelConnected(ctx, e);      }      @Override      public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {          e.getCause().printStackTrace();          Channel ch = e.getChannel();          ch.close();      }  }

Client

package com.roger.java.pattrn.reactor;import java.net.InetSocketAddress;import java.util.concurrent.Executors;import org.jboss.netty.bootstrap.ClientBootstrap;import org.jboss.netty.channel.ChannelFactory;import org.jboss.netty.channel.ChannelFuture;import org.jboss.netty.channel.ChannelPipeline;import org.jboss.netty.channel.ChannelPipelineFactory;import org.jboss.netty.channel.Channels;import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;import org.jboss.netty.handler.codec.string.StringDecoder;import org.jboss.netty.handler.codec.string.StringEncoder;public class TimeClient {    public static void main(String[] args) throws Exception {          ChannelFactory factory = new NioClientSocketChannelFactory(          Executors.newCachedThreadPool(),          Executors.newCachedThreadPool());          ClientBootstrap bootstrap = new ClientBootstrap(factory);          bootstrap.setPipelineFactory(new ChannelPipelineFactory() {          public ChannelPipeline getPipeline() {                  ChannelPipeline pipeline = Channels.pipeline();                  pipeline.addLast("encode",new StringEncoder());                  pipeline.addLast("decode",new StringDecoder());                  pipeline.addLast("handler",new TimeClientHandler());                return pipeline;              }          });          bootstrap.setOption("tcpNoDelay" , true);          bootstrap.setOption("keepAlive", true);          ChannelFuture future = bootstrap.connect(new InetSocketAddress("127.0.0.1", 8080));        // Wait until the connection is closed or the connection attempt fails.          future.getChannel().getCloseFuture().awaitUninterruptibly();          // Shut down thread pools to exit.          bootstrap.releaseExternalResources();      }  }

TimeClientHandler

package com.roger.java.pattrn.reactor;import java.io.BufferedReader;import java.io.InputStreamReader;import org.jboss.netty.channel.ChannelHandlerContext;import org.jboss.netty.channel.ChannelStateEvent;import org.jboss.netty.channel.ExceptionEvent;import org.jboss.netty.channel.MessageEvent;import org.jboss.netty.channel.SimpleChannelHandler;public class TimeClientHandler extends SimpleChannelHandler {    private BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));      @Override      public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception{         System.out.println("已经与Server建立连接。。。。");          super.channelConnected(ctx, e);          System.out.println("\n请输入要发送的信息:");         e.getChannel().write(sin.readLine());      }      @Override      public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception{          if (e.getMessage() instanceof String) {              String message = (String) e.getMessage();              System.out.println(message);              System.out.println("\n等待客户端输入。。。");              System.out.println("\n请输入要发送的信息:");             e.getChannel().write(sin.readLine());          }        super.messageReceived(ctx, e);       }      @Override      public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {          e.getCause().printStackTrace();          e.getChannel().close();      }   }
0 0
原创粉丝点击