范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

在springboot项目中集成Netty进行消息发送和接收

  概述
  本文通过一个简单的 demo 来介绍 Netty 在 spring boot 项目中的使用,其中包括了服务器端和客户端的启动代码,客户端向服务器端发送文本消息。 maven 依赖 	io.netty 	netty-all 	4.1.76.Final  关键点服务器端在启动的时候开放一个端口:19080 客户端在启动的时候通过 ip 和 端口连上服务器端 客户端和服务器端都通过 Channel 对象向彼此发送数据 服务器和客户端都通过继承 ChannelInboundHandlerAdapter 类实现对消息的读取和回写等操作 服务器和客户端都通过 StringDecoder 和 StringEncoder 实现对消息的解码和转码操作 服务器和客户端启动的时候都会阻塞当前线程,因此需要在一个单独的线程中进行启动 消息发送的例子本例是一个 spring boot web 项目,项目占用了 8080 端口 服务器端在启动的时候开放 19080 端口( 注意不要和 web 端口冲突了 ) 客户端在启动的时候连上服务器端 通过 web api 向客户端发送数据,客户端再通过 Channel 对象向服务器端发送数据 服务器接收到客户端数据后也通过 Channel 对象向客户端发送数据 server 服务器端通过 @PostConstruct 注解的方法进行启动,具体如下 package com.ckjava.test.server;  import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component;  import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.net.InetSocketAddress; import java.util.concurrent.ForkJoinPool;  @Slf4j @Component public class HelloWorldServer {      private static final EventLoopGroup bossGroup = new NioEventLoopGroup(1);     private static final EventLoopGroup workerGroup = new NioEventLoopGroup();      public void startServer(int port) {         try {             ServerBootstrap sbs = new ServerBootstrap().group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))                     .childHandler(new ChannelInitializer() {                          protected void initChannel(SocketChannel ch) throws Exception { //                            ch.pipeline().addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));                             ch.pipeline().addLast("decoder", new StringDecoder());                             ch.pipeline().addLast("encoder", new StringEncoder());                             ch.pipeline().addLast(new HelloWorldServerHandler());                         }                      }).option(ChannelOption.SO_BACKLOG, 128)                     .childOption(ChannelOption.SO_KEEPALIVE, true);             // 绑定端口,开始接收进来的连接             sbs.bind(port).addListener(future -> {                 log.info(String.format("服务器启动成功,并监听端口:%s ", port));             });          } catch (Exception e) {             log.error("启动 netty 服务器端出现异常", e);         }     }      // 服务器端启动,并绑定 19080 端口     @PostConstruct     public void init() {         ForkJoinPool.commonPool().submit(() -> startServer(19080));     }      @PreDestroy     public void destroy() {         bossGroup.shutdownGracefully();         workerGroup.shutdownGracefully();     } } 服务器端 HelloWorldServerHandler 如下 package com.ckjava.test.server;  import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import lombok.extern.slf4j.Slf4j;  @Slf4j public class HelloWorldServerHandler extends ChannelInboundHandlerAdapter {      // 服务器端读取到 客户端发送过来的数据,然后通过 Channel 回写数据     @Override     public void channelRead(ChannelHandlerContext ctx, Object msg) {         log.info(String.format("服务器端读取到从客户端:%s 发送过来的数据:%s", ctx.channel().remoteAddress(), msg.toString()));         ctx.channel().writeAndFlush(String.format("server write:%s", msg));     }      // 捕获到异常的处理     @Override     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {         cause.printStackTrace();         ctx.close();     }  } client 客户端通过 @PostConstruct 注解的方法进行启动,具体如下 package com.ckjava.test.client;  import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.ChannelPipeline; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component;  import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.util.concurrent.ForkJoinPool;  @Slf4j @Component public class HelloWorldClient {      static final int SIZE = Integer.parseInt(System.getProperty("size", "256"));      private final EventLoopGroup group = new NioEventLoopGroup();     private ChannelFuture mChannelFuture = null;     private final ThreadLocal mChannel = new ThreadLocal<>();      public void startClient(String host, int port) {         // Configure the client.         try {             Bootstrap b = new Bootstrap();             b.group(group)                     .channel(NioSocketChannel.class)                     .option(ChannelOption.TCP_NODELAY, true)                     .handler(new ChannelInitializer() {                         @Override                         public void initChannel(SocketChannel ch) throws Exception {                             ChannelPipeline p = ch.pipeline();                             p.addLast("decoder", new StringDecoder());                             p.addLast("encoder", new StringEncoder());                             p.addLast(new HelloWorldClientHandler());                         }                     });              mChannelFuture = b.connect(host, port).addListener(future -> {                 log.info(String.format("客户端启动成功,并监听端口:%s ", port));             });         } catch (Exception e) {             log.error("启动 netty 客户端出现异常", e);         }     }      /**      * 客户端通过 Channel 对象向服务器端发送数据      * @param data 文本数据      */     public void send(String data) {         try {             if (mChannel.get() == null) {                 mChannel.set(mChannelFuture.channel());             }              mChannel.get().writeAndFlush(data);         } catch (Exception e) {             log.error(this.getClass().getName().concat(".send has error"), e);         }     }      // 客户端启动,并连上服务器端     @PostConstruct     public void init() {         ForkJoinPool.commonPool().submit(() -> startClient("127.0.0.1", 19080));     }      @PreDestroy     public void destroy() {         group.shutdownGracefully();     }  } 客户端 HelloWorldClientHandler 实现如下 package com.ckjava.test.client;  import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import lombok.extern.slf4j.Slf4j;  @Slf4j public class HelloWorldClientHandler extends ChannelInboundHandlerAdapter {      // 客户端激活监听     @Override     public void channelActive(ChannelHandlerContext ctx) {         log.info("客户端激活!");     }      // 客户端读取从服务器端发送过来的消息     @Override     public void channelRead(ChannelHandlerContext ctx, Object msg) {         log.info(String.format("客户端读取从服务器端发送过来的数据:%s", msg));     }      // 捕获异常     @Override     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {         cause.printStackTrace();         ctx.close();     }  } web api 数据发送入口这里只是通过 package com.ckjava.test.web;  import com.ckjava.test.client.HelloWorldClient; import io.swagger.annotations.Api; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController;  import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;  /**  * @author ckjava  * @date 2022/4/18 23:50  */ @Api @RequestMapping(produces = "application/json;charset=utf-8") @RestController public class HelloNettyCtrl {      @Resource     private HelloWorldClient mHelloWorldClient;      @GetMapping("/nettyClient")     public void nettyClient(@RequestParam String data) throws Exception {         mHelloWorldClient.send(data);     } }  测试执行如下请求 curl -X GET "http://localhost:8080/nettyClient?data=%E4%BD%A0%E5%A5%BD%20ckjava" -H "accept: application/json;charset=utf-8" 输出如下 22:36:00.178 [nioEventLoopGroup-4-1] INFO  c.c.t.server.HelloWorldServerHandler - 服务器端读取到从客户端:/127.0.0.1:9196 发送过来的数据:你好 ckjava 22:36:00.178 [nioEventLoopGroup-2-1] INFO  c.c.t.client.HelloWorldClientHandler - 客户端读取从服务器端发送过来的数据:server write:你好 ckjava

俄罗斯研发猴痘病毒检测盒已完成实验室测试俄罗斯矢量病毒学与生物技术国家科学中心(下称矢量中心)科研人员研制出了一种自动操作的检测试剂盒(下称检测盒),可用于检测包括猴痘病毒在内的正痘病毒。针对该检测盒的实验室测试已顺利完nssm,一个可以把任何exe注册为系统服务的利器在Windows下把一个exe可执行文件注册为系统服务有很多种方法,常用的有sc命令instsrvsrvany以及本文重点介绍的nssm。引言这阵子为单位编写了一个小工具,作用是禁是时候放弃燃油车?小鹏P5给出了答案中国从不缺乏造车狂人。早年间,李书福曾放出豪言,称汽车就是两排沙发加四个轮子。人们对此一笑了之,却万万没想到,20年后吉利长城比亚迪变身为国人的骄傲。今天,老剧本正在重演。有人讽刺大型超市为何出现关闭潮?大家有没有留意到,最近上超市购物的频率没有以前那么多了,日常生活都是社区团购比较多,周边的大型商场人流越来越少了,没有以前那种繁华的景象了。商业变幻时代沉浮,随着互联网电商新零售的永辉超市全渠道数字化转型策略打造科技永辉科学技术是第一生产力,科技的飞速发展给人类经济发展带来了极大的推动。永辉超市在今年九月提出科技永辉战略,坚定执行全渠道数字化转型策略,通过数字化手段,逐步实现三个30的落地,分别是建筑行业数字化转型用互联网思维数字化理念重新定义建筑产品建筑业是一个古老的行业,同时又是一个崭新的行业,新时代背景下,互联网大数据云计算BIM技术,都在不断的冲击着建筑业,这是一个很缺数据的行业,如何乘上数字化的东风,在新时代让新建筑变typescript学习15对象类型JavaScript里面使用对象来传递数据,TypeScript里面称这个为对象类型。对象类型可以使用三种方式来定义1。匿名方式2。interface类型3。别名方式匿名方办移动套餐我被贷款3年编辑同志2021年6月30号,我去移动公司营业厅办个副卡,营业员给我推了一个98元购机套餐,当时只说3年不能换号码,是和包支付。要不是我去年要贷款根本不知道是一笔贷款,还分期每月从华人首富赵长鹏,真的一夜返贫了吗?有行业人士认为,币圈暴涨暴跌是常态,这也导致赵长鹏的身价波动较大。而在全球对加密货币严监管以及美联储加息的背景下,不排除未来赵长鹏身价再度大幅缩水。返贫了(Pooragain)。5无人叉车4。9万起,中力智能搬运新模式导入成本有多低中力致力于打造全流程全方位全面数字化的物料搬运元宇宙。文叶家淇近期,浙江中力股份有限公司(以下简称中力)对外发布了场内物流五大新模式及智金刚移动机器人新品,旨在通过高效的人机协同模你知道2001年最赚钱的互联网项目竟是移动梦网吗?本文来自浪潮三十年之第八章2001惊天逆转未经容许请勿转载2000年9月以来,中国互联网产业正在度过一个有史以来最寒冷的冬天。与此同时,移动热浪正在席卷中国,小灵通的出现让移动通讯
低调而实用的座驾比亚迪e2,不足10万起,续航401km,关键颜值高预算10万左右选一台纯电动汽车,当下有很多车型可以考虑,比如说欧拉旗下车型都很合适,除了好猫可能略贵一些,再就是哪吒三兄弟,也都十分符合10万预算这一要求。但是如果各位对车型级别有何小鹏,小鹏汽车创始人,不甘空虚和痛苦的创业者何小鹏,小鹏汽车创始人,从软件到硬件,从移动互联网到汽车,何小鹏身上充满了创业基因。1977年,何小鹏出生在湖北黄石的一个普通工人家庭,为了帮家里减轻经济负担,他很小的时候,就开始中国新能源汽车真的能弯道超车吗?为什么说奇瑞DHT世界领先2015年,一家名为驱动系统设计(DriveSystemDesign)的公司(以下简称为DSD)正在全球寻求投资者,其目的是为了将该公司最新研发的一款多齿比变速箱实现商业化应用。我2030万新能源轿车该选谁?不如看看长续航高品质的极狐S最近,极狐这个北汽旗下的高端电动品牌随着一场第三方媒体的对撞测试,进入了许多购车消费者的视野。其新款轿车极狐S在和另一台价位接近的新能源车的对撞中,无论是车身结构车身强度还是电池包特斯拉造了一台能跳舞的机器人?结果被骂放屁在近日举办的特斯拉AI日上,特斯拉推出了两款新品,Dojo超级计算机D1芯片,以及特斯拉机器人。大家都知道,现在各家车企都没有完全实现L4L5级别的自动驾驶,因为路况环境太复杂了,十荟团点中社区团购生穴社区团购的风向变了。自去年年末以来,监管部门重拳出击,叫停补贴无序扩张等乱象,无论是新入局的互联网巨头,还是早就入局的赛道玩家,都被倒逼反思并重构自己未来的发展路径。8月21日,十最没有存在感的OV竟是国内手机销量前二?今天看新闻,发现OPPO和VIVO竟然是国内手机销量前二,一直被大部分网友定义成高价低配的品牌,却在国内如此受欢迎。而在今年的618购物节期间,中国智能手机销量冠军也是被VIVO拿iPhone再次落后,苹果开始测试屏下指纹识别屏下指纹识别技术对于Android手机用户并不陌生,由一开始只在旗舰级手机提供,到现在不少中阶手机也已配备。最近有消苹果终于开始测试屏下指纹识别技术,并考虑引进到iPhone去。现特斯拉发布人形机器人TeslaBot特斯拉发布人形机器人TeslaBot特斯拉在我们印象中是一家做新能源汽车无人驾驶的科技公司,这次它跳出了圈子。在8。20的上午特斯拉AI日发布会上,马斯克向全世界发布了名叫Tesl不要想太多马斯克的特斯拉机器人或许是个笑话在对特斯拉在人工智能方面所做的无可否认的令人印象深刻的工作进行了密集的介绍之后,该公司自封的Technoking埃隆马斯克(ElonMusk)带来了一位身着氨纶套装的舞者,为当晚画大佬出手即王炸!三星推出DDR57200内存,单条就有512GB随着Intel十二代酷睿离发布的时间越来越近,其他厂商也开始在配套的硬件上开始投入。对于新平台而言,除了处理器和主板之外,另一个不可或缺的就是内存了。尽管十二代酷睿同时支持DDR4