Netty快速入门
什么是Netty
Netty 是一个基于 JAVA NIO 类库的异步通信框架,它的架构特点是:异步非阻塞、基于事件驱动、高性能、高可靠性和高可定制性。
Netty应用场景
1.分布式开源框架中dubbo、Zookeeper,RocketMQ底层rpc通讯使用就是netty。
2.游戏开发中,底层使用netty通讯。
为什么选择netty
在本小节,我们总结下为什么不建议开发者直接使用JDK的NIO类库进行开发的原因:
1) NIO的类库和API繁杂,使用麻烦,你需要熟练掌握Selector、ServerSocketChannel、SocketChannel、ByteBuffer等;
2) 需要具备其它的额外技能做铺垫,例如熟悉Java多线程编程,因为NIO编程涉及到Reactor模式,你必须对多线程和网路编程非常熟悉,才能编写出高质量的NIO程序;
3) 可靠性能力补齐,工作量和难度都非常大。例如客户端面临断连重连、网络闪断、半包读写、失败缓存、网络拥塞和异常码流的处理等等,NIO编程的特点是功能开发相对容易,但是可靠性能力补齐工作量和难度都非常大;
4) JDK NIO的BUG,例如臭名昭著的epoll bug,它会导致Selector空轮询,最终导致CPU 100%。官方声称在JDK1.6版本的update18修复了该问题,但是直到JDK1.7版本该问题仍旧存在,只不过该bug发生概率降低了一些而已,它并没有被根本解决。该BUG以及与该BUG相关的问题单如下:
Netty服务器端
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class ServerHandler extends SimpleChannelHandler { /** * 通道关闭的时候触发 */ @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { System.out.println("channelClosed"); } /** * 必须是连接已经建立,关闭通道的时候才会触发. */ @Override public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { super.channelDisconnected(ctx, e); System.out.println("channelDisconnected"); } /** * 捕获异常 */ @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { super.exceptionCaught(ctx, e); System.out.println("exceptionCaught"); } /** * 接受消息 */ public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { super.messageReceived(ctx, e); // System.out.println("messageReceived"); System.out.println("服务器端收到客户端消息:"+e.getMessage()); //回复内容 ctx.getChannel().write("好的"); } } // netty 服务器端 public class NettyServer { public static void main(String[] args) { // 创建服务类对象 ServerBootstrap serverBootstrap = new ServerBootstrap(); // 创建两个线程池 分别为监听监听端口 ,nio监听 ExecutorService boos = Executors.newCachedThreadPool(); ExecutorService worker = Executors.newCachedThreadPool(); // 设置工程 并把两个线程池加入中 serverBootstrap.setFactory(new NioServerSocketChannelFactory(boos, worker)); // 设置管道工厂 serverBootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = Channels.pipeline(); //将数据转换为string类型. pipeline.addLast("decoder", new StringDecoder()); pipeline.addLast("encoder", new StringEncoder()); pipeline.addLast("serverHandler", new ServerHandler()); return pipeline; } }); // 绑定端口号 serverBootstrap.bind(new InetSocketAddress(9090)); System.out.println("netty server启动...."); } }
Netty客户端
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.itmayiedu; import java.net.InetSocketAddress; import java.util.Scanner; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.handler.codec.string.StringDecoder; import org.jboss.netty.handler.codec.string.StringEncoder; class ClientHandler extends SimpleChannelHandler { /** * 通道关闭的时候触发 */ @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { System.out.println("channelClosed"); } /** * 必须是连接已经建立,关闭通道的时候才会触发. */ @Override public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { super.channelDisconnected(ctx, e); System.out.println("channelDisconnected"); } /** * 捕获异常 */ @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { super.exceptionCaught(ctx, e); System.out.println("exceptionCaught"); } /** * 接受消息 */ public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { super.messageReceived(ctx, e); // System.out.println("messageReceived"); System.out.println("服务器端向客户端回复内容:"+e.getMessage()); //回复内容 // ctx.getChannel().write("好的"); } } public class NettyClient { public static void main(String[] args) { System.out.println("netty client启动..."); // 创建客户端类 ClientBootstrap clientBootstrap = new ClientBootstrap(); // 线程池 ExecutorService boos = Executors.newCachedThreadPool(); ExecutorService worker = Executors.newCachedThreadPool(); clientBootstrap.setFactory(new NioClientSocketChannelFactory(boos, worker)); clientBootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = Channels.pipeline(); // 将数据转换为string类型. pipeline.addLast("decoder", new StringDecoder()); pipeline.addLast("encoder", new StringEncoder()); pipeline.addLast("clientHandler", new ClientHandler()); return pipeline; } }); //连接服务端 ChannelFuture connect = clientBootstrap.connect(new InetSocketAddress("127.0.0.1", 9090)); Channel channel = connect.getChannel(); System.out.println("client start"); Scanner scanner= new Scanner(System.in); while (true) { System.out.println("请输输入内容..."); channel.write(scanner.next()); } } }