# springboot集成netty ##1 Netty是什么? Netty是由JBOSS提供的一个java开源框架,现为 Github上的独立项目。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。 也就是说,Netty 是一个基于NIO的客户端、服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户、服务端应用。Netty相当于简化和流线化了网络应用的编程开发过程,例如:基于TCP和UDP的socket服务开发。 “快速”和“简单”并不用产生维护性或性能上的问题。Netty 是一个吸收了多种协议(包括FTP、SMTP、HTTP等各种二进制文本协议)的实现经验,并经过相当精心设计的项目。最终,Netty 成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和伸缩性。 ##2 集成步骤 ###步骤1:Pom.xml添加依赖 ```angular2 <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.43.Final</version> </dependency> ``` ###步骤2:NettyServer类 ```angular2 @Component @Slf4j @Data public class NettyServer { private final ConcurrentHashMap<String,ChannelHandlerContext> channels = new ConcurrentHashMap<>(); private final NioEventLoopGroup boss = new NioEventLoopGroup(); private final NioEventLoopGroup worker = new NioEventLoopGroup(); private Channel channel; //启动服务 public ChannelFuture run(InetSocketAddress address){ ChannelFuture cf = null; try { ServerBootstrap server = new ServerBootstrap(); server.group(boss,worker) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG,128) .childOption(ChannelOption.SO_KEEPALIVE,true) .childHandler(new ChannelInitializer<SocketChannel>(){ @Override protected void initChannel(SocketChannel socketChannel) throws Exception { // 解码编码 socketChannel.pipeline().addLast(new StringDecoder(CharsetUtil.UTF_8)); socketChannel.pipeline().addLast(new StringEncoder(CharsetUtil.UTF_8)); socketChannel.pipeline().addLast(new SimpleChannelInboundHandler<Object>(){ @Override public void channelRead0(ChannelHandlerContext ctx, Object msg) { System.out.println("server receive message :"+ msg); ctx.channel().writeAndFlush("yes server already accept your message" + msg); // ctx.close(); } @Override public void channelActive(ChannelHandlerContext ctx) { System.out.println("channelActive>>>>>>>>"); if(channels.get(ctx.channel().id().toString())==null){ channels.put(ctx.channel().id().toString(),ctx); }else{ System.out.println(ctx.channel().id().toString()+"已经放进通道列表了"); } } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { System.out.println(ctx.channel().localAddress().toString() + " 通道不活跃!已关闭"); removeChannnelMap(ctx); // 关闭流 ctx.close(); } private void removeChannnelMap(ChannelHandlerContext ctx){ Iterator<Map.Entry<String,ChannelHandlerContext>> iterator = channels.entrySet().iterator(); while (iterator.hasNext()){ Map.Entry<String,ChannelHandlerContext> ele = iterator.next(); if(ctx.channel().id().toString().equals(ele.getKey())){ channels.remove(ele); } } } @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { super.userEventTriggered(ctx, evt); if (evt instanceof IdleStateEvent) { IdleStateEvent event = (IdleStateEvent) evt; if (event.state().equals(IdleState.READER_IDLE)) ctx.close(); //标志该链接已经close 了 } } }); } }); cf = server.bind(address).syncUninterruptibly(); channel = cf.channel(); }catch (Exception e) { log.error("Netty start error:", e); } finally { if (cf != null && cf.isSuccess()) { log.info("Netty server listening " + address.getHostName() + " on port " + address.getPort() + " and ready for connections..."); } else { log.error("Netty server start up Error!"); } } return cf; } public void destroy() { log.info("Shutdown Netty Server..."); if(channel != null) { channel.close();} worker.shutdownGracefully(); boss.shutdownGracefully(); log.info("Shutdown Netty Server Success!"); } } ``` ###步骤3:启动Netty服务 在spring启动类里启动Netty服务,实现netty服务端与客户端消息收发。 其中,如果要实现服务端向客户端主动发消息,需要启动一个异步线程,见步骤4 ```angular2 @SpringBootApplication public class SwaggerApplication implements CommandLineRunner { @Autowired private NettyServer socketServer; @Autowired private NettyConfigration config; @Autowired private AsyncTaskService task;//loop channels实现服务端向客户端消息发送 public static void main(String[] args) { SpringApplication.run(SwaggerApplication.class, args); } @Override public void run(String... args) throws Exception { InetSocketAddress address = new InetSocketAddress(config.getPort()); ChannelFuture future = socketServer.run(address); task.executeAsyncTask(socketServer); Runtime.getRuntime().addShutdownHook(new Thread(){ @Override public void run() { socketServer.destroy(); } }); future.channel().closeFuture().syncUninterruptibly(); } } ``` ###步骤4:channel轮询异步线程AsyncTaskService ```angular2 @Service @Slf4j public class AsyncTaskService { @Async // 表明是异步方法 // 无返回值 public void executeAsyncTask(NettyServer socketServer) { System.out.println("开启新线程执行channels loop"); new Thread(()->{ ConcurrentHashMap<String, ChannelHandlerContext> channels = socketServer.getChannels(); try { while (true){ Thread.sleep(5000); Iterator<Map.Entry<String,ChannelHandlerContext>> iterator = channels.entrySet().iterator(); while (iterator.hasNext()){ Map.Entry<String,ChannelHandlerContext> ele = iterator.next(); ele.getValue().channel().write(new Date()+"::server 主动发了一条消息给你,收到了吗?"); ele.getValue().channel().flush(); } } }catch (InterruptedException e){ } }).start(); } } ``` ###步骤5:客户端测试类NettyClient ```angular2 public class NettyClient { public static void main(String[] args) throws InterruptedException { Bootstrap bootstrap = new Bootstrap(); NioEventLoopGroup group = new NioEventLoopGroup(); bootstrap.group(group) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<Channel>() { @Override protected void initChannel(Channel ch) { ch.pipeline().addLast(new StringEncoder()); ch.pipeline().addLast(new SimpleChannelInboundHandler() { @Override public void channelRead0(ChannelHandlerContext channelHandlerContext, Object o) throws Exception { System.out.println(convertByteBufToString((ByteBuf)o)); } }); } }); Channel channel = bootstrap.connect("127.0.0.1", 11111).channel(); while (true) { channel.writeAndFlush(new Date() + ": hello world!"); Thread.sleep(2000); } } public static String convertByteBufToString(ByteBuf buf) { String str; if(buf.hasArray()) { // 处理堆缓冲区 str = new String(buf.array(), buf.arrayOffset() + buf.readerIndex(), buf.readableBytes()); } else { // 处理直接缓冲区以及复合缓冲区 byte[] bytes = new byte[buf.readableBytes()]; buf.getBytes(buf.readerIndex(), bytes); str = new String(bytes, 0, buf.readableBytes()); } return str; } } ```
springboot集成Netty
最新推荐文章于 2024-08-04 00:00:35 发布