最新要闻
- 【聚看点】誉的拼音和组词怎么写_誉的拼音
- 698元!华为儿童手表5发布:无网离线也能定位
- 数毛社Steam Deck测评:新三A大作性能表现开始吃紧
- 一次装修十年无忧!华为全屋智能4.0发布:业界首款空间穿越屏|全球热消息
- 每日聚焦:4K旗舰领衔!Vidda连发三款投影仪:画质、亮度直接拉满 3199元起
- 81岁老妪拒绝医美|今日报
- 海通恒信(01905):“21恒信G2”回售登记期为5月23日至25日
- 【世界独家】阿里巴巴核心业务:云智能部门将成为独立上市公司
- 热点!车企们 请别拿人命开玩笑
- 华为十大新品价格汇总:MateBook X Pro笔记本顶配1.4万元-天天即时
- 三大专业升级 华为MateBook 16s 2023来了:重度生产力标杆之作
- 业界首款支持高血糖!华为WATCH 4 Pro蔚蓝地球图赏 当前快看
- 全球热文:win7屏幕保护设置在哪里 win7屏幕保护设置
- 每日快讯!凯华推出“黑莓冰淇淋”轴体:加长轴心敲击更清脆
- 全球速读:北斗导航年产值超5000亿元!12nm芯片重大突破
- 摩托“骑士”双手离把耍酷还发抖音炫技 被“顺网线”找到_今亮点
广告
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
Springboot集成Netty实现TCP通讯_天天速看料
(资料图片)
Netty测试客户端
package com.coremain;import com.coremain.handler.ServerListenerHandler;import io.netty.bootstrap.Bootstrap;import io.netty.buffer.Unpooled;import io.netty.channel.Channel;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelInitializer;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.util.CharsetUtil;import java.util.Scanner;/** * @description: 测试 * @author: GuoTong * @createTime: 2023-05-14 16:46 * @since JDK 1.8 OR 11 **/public class NettyClientTest { public static void main(String[] args) throws InterruptedException { // 客户端的线程池 EventLoopGroup workerGroup = new NioEventLoopGroup(8); try { // 创建Netty客户端端的启动对象 Bootstrap bootstrap = new Bootstrap(); // 使用链式编程来配置参数 bootstrap.group(workerGroup) .channel(NioSocketChannel.class).handler(new ChannelInitializer() { @Override protected void initChannel(SocketChannel ch) throws Exception { //对workerGroup的SocketChannel设置处理器 ChannelPipeline pipeline = ch.pipeline(); // 对于通道加入解码器 pipeline.addLast("decoder", new StringDecoder()); // 对于通道加入加码器 pipeline.addLast("encoder", new StringDecoder()); // 加入事件回调处理器 pipeline.addLast(new ServerListenerHandler()); } }); System.out.println("基于Netty的客户端接入启动完成...."); ChannelFuture cf = bootstrap.connect("127.0.0.1", 18023).sync(); // 获取连接通道 Channel channel = cf.channel(); System.out.println("+++++++" + channel.localAddress() + "======="); // 客户端输入扫描器 Scanner scanner = new Scanner(System.in); while (scanner.hasNext()) { String next = scanner.next(); // 发送到服务端 channel.writeAndFlush(Unpooled.buffer().writeBytes(next.getBytes(CharsetUtil.UTF_8))); } // 通过sync方法同步等待通道关闭处理完毕,这里会阻塞等待通道关闭完成,内部调用的是Object的wait()方法 cf.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); } }}
Netty的Server启动类
package com.coremain.netty;import com.coremain.handler.NettyServerHTTPHandler;import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelOption;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.nio.NioServerSocketChannel;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;import javax.annotation.PreDestroy;/** * @description: Netty服务启动器 * netty服务端会跟随一起启动。 同时,在springboot关闭前,会先销毁netty服务。 * @author: GuoTong * @createTime: 2023-05-14 15:13 * @since JDK 1.8 OR 11 **/@Componentpublic class NettyServerHTTPRunning { // log4j2的AsyncLogger本身的逻辑采用了缓冲区思想,使用的是disruptor框架来实现一个环形无锁队列。 private static final Logger log = LoggerFactory.getLogger(NettyServerHTTPRunning.class); /** * 主线程组 */ private NioEventLoopGroup bossGroup = new NioEventLoopGroup(1); /** * 工作线程组 */ private NioEventLoopGroup workerGroup = new NioEventLoopGroup(10); /** * (http)主要服务端口 */ @Value("${iot.port1:18024}") private int iot1; /** * (http)备用服务端口 */ @Value("${iot.port2:18025}") private int iot2; /** * 启动 netty 服务 */ @PostConstruct public void startServer() throws InterruptedException { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) // 三次握手中的A、B队列总和最大值(第二次握手加入A, 第三次握手从A移动到B, accept 后从B取出) .option(ChannelOption.SO_BACKLOG, 1024) // 解决端口占用问题, 可以共用服务器端口(即使该端口已被其他端口占用) .option(ChannelOption.SO_REUSEADDR, true) // 接收消息缓冲区大小 .option(ChannelOption.SO_RCVBUF, 2048) // 发送消息缓冲区大小 .option(ChannelOption.SO_SNDBUF, 2048) // 用于启用或关于Nagle算法。如果要求高实时性,有数据发送时就马上发送,就将该选项设置为true关闭Nagle算法; // 如果要减少发送次数减少网络交互,就设置为false等累积一定大小后再发送 .option(ChannelOption.TCP_NODELAY, true) // 用于检测长时间没有数据传输的连接状态,当设置该选项以后,如果在两小时内没有数据的通信时,TCP会自动发送一个活动探测数据报文 .option(ChannelOption.SO_KEEPALIVE, true) // 当用户调用close()方法的时候,函数返回,在可能的情况下,尽量发送数据,不一定保证全部发送成功 // 使用SO_LINGER可以阻塞close()的调用时间,直到数据完全发送 .option(ChannelOption.SO_LINGER, 2000) .childHandler(new NettyServerHTTPHandler()); ChannelFuture service1 = serverBootstrap.bind(iot1).sync(); ChannelFuture service2 = serverBootstrap.bind(iot2).sync(); if (service1.isSuccess()) { log.info("服务1启动成功, port: {}", iot1); } if (service2.isSuccess()) { log.info("服务2启动成功, port: {}", iot2); } } /** * 销毁 */ @PreDestroy public void destroy() { bossGroup.shutdownGracefully().syncUninterruptibly(); workerGroup.shutdownGracefully().syncUninterruptibly(); log.info("关闭 Netty 成功"); }}
Netty的服务端核心类:ServerBootstrap
package com.coremain.config;import com.coremain.handler.NettyServerHandler;import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.ChannelOption;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.nio.NioServerSocketChannel;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/** * @description: 配置NettyServer * @author: GuoTong * @createTime: 2023-05-14 14:54 * @since JDK 1.8 OR 11 **/@Configuration@EnableConfigurationPropertiespublic class NettyConfig { private final NettyProperties nettyProperties; public NettyConfig(NettyProperties nettyProperties) { this.nettyProperties = nettyProperties; } /** * boss线程池-进行客户端连接 * * @return */ @Bean public NioEventLoopGroup boosGroup() { return new NioEventLoopGroup(nettyProperties.getBoss()); } /** * worker线程池-进行业务处理 * * @return */ @Bean public NioEventLoopGroup workerGroup() { return new NioEventLoopGroup(nettyProperties.getWorker()); } /** * 服务端启动器,监听客户端连接 * * @return */ @Bean public ServerBootstrap serverBootstrap() { ServerBootstrap serverBootstrap = new ServerBootstrap() // 指定使用的线程组 .group(boosGroup(), workerGroup()) // 指定使用的通道 .channel(NioServerSocketChannel.class) // 三次握手中的A、B队列总和最大值(第二次握手加入A, 第三次握手从A移动到B, accept 后从B取出) .option(ChannelOption.SO_BACKLOG, 1024) // 指定连接超时时间 .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, nettyProperties.getTimeout()) // 支持长连接 .option(ChannelOption.SO_KEEPALIVE, true) // 接收消息缓冲区大小 .option(ChannelOption.SO_RCVBUF, 2048) // 发送消息缓冲区大小 .option(ChannelOption.SO_SNDBUF, 2048) // 指定worker处理器 .childHandler(new NettyServerHandler()); return serverBootstrap; }}
Netty的通道处理器 ChannelInitializer
package com.coremain.handler;import io.netty.buffer.ByteBuf;import io.netty.buffer.Unpooled;import io.netty.channel.ChannelHandler;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelPipeline;import io.netty.channel.socket.SocketChannel;import io.netty.handler.codec.DelimiterBasedFrameDecoder;import org.springframework.stereotype.Component;/** * @description: Netty服务端回调处理 * @ChannelHandler.Sharable。这个注解的作用是标注一个Handler实例可以被多个通道安全地共享。 * @author: GuoTong * @createTime: 2023-05-14 14:57 * @since JDK 1.8 OR 11 **/@ChannelHandler.Sharable@Componentpublic class NettyServerHandler extends ChannelInitializer { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { // 数据分割符 String delimiterStr = "##@##"; ByteBuf delimiter = Unpooled.copiedBuffer(delimiterStr.getBytes()); ChannelPipeline pipeline = socketChannel.pipeline(); // 使用自定义处理拆包/沾包,并且每次查找的最大长度为1024字节 pipeline.addLast(new DelimiterBasedFrameDecoder(1024, delimiter)); // 将上一步解码后的数据转码为Message实例 pipeline.addLast(new MessageUTF8DecodeHandler()); // 对发送客户端的数据进行编码,并添加数据分隔符 pipeline.addLast(new MessageUTF8EncodeHandler(delimiterStr)); // 对数据进行最终处理 pipeline.addLast(new ServerListenerHandler()); }}
Netty回调处理器SimpleChannelInboundHandler
package com.coremain.handler;import com.coremain.handler.bean.MessageEnum;import io.netty.channel.ChannelHandler;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.SimpleChannelInboundHandler;import io.netty.channel.socket.SocketChannel;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;import java.time.LocalDateTime;/** * @description: 数据处理器,针对不同类型数据分类处理 在处理不同接收数据时使用了枚举类型 * @ChannelHandler.Sharable。这个注解的作用是标注一个Handler实例可以被多个通道安全地共享。 * @author: GuoTong * @createTime: 2023-05-14 15:07 * @since JDK 1.8 OR 11 **/@ChannelHandler.Sharable@Componentpublic class ServerListenerHandler extends SimpleChannelInboundHandler { private static final Logger log = LoggerFactory.getLogger(ServerListenerHandler.class); /** * 当客户端主动链接服务端的链接后,这个通道就是活跃的了。也就是客户端与服务端建立了通信通道并且可以传输数据 */ @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { SocketChannel channel = (SocketChannel) ctx.channel(); String currentData = LocalDateTime.now().format(CommonUtilHandler.dateTimeFormatter); //通知客户端链接建立成功 String str = "通知客户端链接建立成功" + " " + currentData + " " + channel.localAddress().getHostString() + "\r\n"; ctx.writeAndFlush(str); } /** * 设备接入连接时处理 * * @param ctx */ @Override public void handlerAdded(ChannelHandlerContext ctx) { log.info("有新的连接:[{}]", ctx.channel().id().asLongText()); } /** * 数据处理 * * @param ctx * @param msg */ @Override protected void channelRead0(ChannelHandlerContext ctx, MessageStrUTF8 msg) { // 获取消息实例中的消息体 String content = msg.getContent(); // 对不同消息类型进行处理 MessageEnum type = MessageEnum.getStructureEnum(msg); String currentData = LocalDateTime.now().format(CommonUtilHandler.dateTimeFormatter); switch (type) { case CONNECT: // TODO 心跳消息处理 case STATE: // TODO 设备状态 default: log.info(currentData + type.content + " 消息内容" + content); } } /** * 设备下线处理 * * @param ctx */ @Override public void handlerRemoved(ChannelHandlerContext ctx) { log.info("设备下线了:{}", ctx.channel().id().asLongText()); } /** * 当客户端主动断开服务端的链接后,这个通道就是不活跃的。也就是说客户端与服务端的关闭了通信通道并且不可以传输数据 */ @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { log.info("客户端断开链接{}", ctx.channel().localAddress().toString()); } /** * 设备连接异常处理 * * @param ctx * @param cause */ @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); // 打印异常 log.info("异常:{}", cause.getMessage()); // 关闭连接 ctx.close(); }}
maven依赖
org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-logging org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-tomcat org.springframework.boot spring-boot-starter-undertow org.projectlombok lombok 1.18.16 junit junit 4.12 test org.springframework.boot spring-boot-starter-log4j2 com.lmax disruptor ${disruptor-version} io.netty netty-all 4.1.68.Final com.alibaba.fastjson2 fastjson2 ${fastJson-version}
项目结构
日志配置文件 log4j2.xml
./NettyStudy/log4j2 application %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level [%L] - %msg%n 20MB
配置文件 application.yml
# netty 配置netty: # boss线程数量 boss: 4 # worker线程数量 worker: 2 # 连接超时时间 timeout: 6000 # 服务器主端口 port: 18023 # 服务器备用端口 portSalve: 18026 # 服务器地址 host: 127.0.0.1spring: application: name: netty-server mvc: servlet: load-on-startup: 1 #项目启动时执行初始化即可解决。server: port: 15026 undertow: accesslog: enabled: false direct-buffers: true # 是否分配的直接内存(NIO直接分配的堆外内存) buffer-size: 1024 #每块buffer的空间大小,越小的空间被利用越充分 threads: worker: 20 # 阻塞任务线程池, 它的值设置取决于系统线程执行任务的阻塞系数,默认值是IO线程数*8 io: 4 # CPU有几核,就填写几。 servlet: context-path: /undertow
启动Netty服务端
启动Netty客户端
客户端发送消息
服务端收到
关键词:
-
Springboot集成Netty实现TCP通讯_天天速看料
Netty测试客户端packagecom coremain;importcom coremain handler ServerListenerHandler;importio netty b
来源: Springboot集成Netty实现TCP通讯_天天速看料
【聚看点】誉的拼音和组词怎么写_誉的拼音
698元!华为儿童手表5发布:无网离线也能定位
数毛社Steam Deck测评:新三A大作性能表现开始吃紧
一次装修十年无忧!华为全屋智能4.0发布:业界首款空间穿越屏|全球热消息
每日聚焦:4K旗舰领衔!Vidda连发三款投影仪:画质、亮度直接拉满 3199元起
81岁老妪拒绝医美|今日报
海通恒信(01905):“21恒信G2”回售登记期为5月23日至25日
【世界独家】阿里巴巴核心业务:云智能部门将成为独立上市公司
热点!车企们 请别拿人命开玩笑
华为十大新品价格汇总:MateBook X Pro笔记本顶配1.4万元-天天即时
三大专业升级 华为MateBook 16s 2023来了:重度生产力标杆之作
业界首款支持高血糖!华为WATCH 4 Pro蔚蓝地球图赏 当前快看
全球热文:win7屏幕保护设置在哪里 win7屏幕保护设置
ET介绍——强大的基于.dotnet7+Unity3d的双端C#开源游戏框架-全球报资讯
热推荐:Java设计模式-外观模式
python包管理工具:Conda和pip比较
债市日报:5月18日
每日快讯!凯华推出“黑莓冰淇淋”轴体:加长轴心敲击更清脆
全球速读:北斗导航年产值超5000亿元!12nm芯片重大突破
摩托“骑士”双手离把耍酷还发抖音炫技 被“顺网线”找到_今亮点
安卓用户正在加速逃离:为何买苹果手机的人越来越多了?
1499元起 努比亚N5发布:6nm国产芯 今日报
煜邦电力: 关于回复上海证券交易所《关于北京煜邦电力技术股份有限公司向不特定对象发行可转换公司债券的审核中心意见落实函》的公告
热文:【一步步开发AI运动小程序】一、准备工作
python标准模块介绍 -Base64: Base64, Base85等数据编码|全球时讯
学系统集成项目管理工程师(中项)系列22b_信息化知识(中)
express框架的基本使用 环球新资讯
幺妹带你慢慢耍歌词完整版_请问老师们有谁知道幺妹带你慢慢耍歌词曲谱 这首歌确实不错好听
拒绝录用有文身员工 老板回应被威胁:看不惯年轻人必教育到底
滚动:《塞尔达传说:王国之泪》掉帧严重:任天堂Switch性能不够用了
排面!理想L7成卢森堡大使馆官方用车:“这是中国最棒的车”_关注
环球今日讯!预制半成品、来“料”加工、网上销售 普陀警方捣毁一伪造、买卖身份证件黑色产业链
论文、专利、文献检索及图像数据工具总结 时讯
工控老曹说——TSN标准化如何赋能多领域以太网新发展
焦点讯息:2023最佳python编辑器和IDE
git 常用指令-当前聚焦
今日精选:万家基金尹诚庸离任6只基金
iQOO首款降噪无线耳机来了:将与Neo8系列同步推出
悲惨的5G基站:你敢建?我就敢拆!
害怕失去灵魂?大众汽车:我们没使用华为车机软件|环球快讯
焦点热议:小黑旗舰升级13代酷睿!联想2023款ThinkPad X1 Carbon国内发布
世界快看点丨马斯克再度催生:再不生娃人类就要灭亡了
苏联题材科幻动作游戏《原子之心》Steam 史低促销
微服务圣经1:零基础搭建一套SpringCloud微服务脚手架(SpringCloud+Dubbo+Docker+Jenkins) 环球速递
低代码开发——进最热的赛道,啃最硬的骨头-视焦点讯
Python字符串替换的3种方法-播资讯
Django SQL注入漏洞复现 (CVE-2022-28347)
每日机构分析:5月18日
天天热资讯!斗罗大陆:为何唐三成为海神后,只赠予了吉祥一个神赐魂环,
我国本月将发射神舟十六号载人飞船:与神舟十五号乘组在轨交接-消息
【世界速看料】充电时 先插手机还是充电器?这几种方法都错了
正面挑战微软!谷歌宣布将推出AI写代码功能
来了!消息称RTX 4060 Ti今晚发布:NV定8/16GB版价格 或399美元
环球今头条!小米13旗舰主摄下放!小米Civi 3关键参数曝光:IMX800加持
陈张开展“进企业促发展”人大代表履职建功主题活动 焦点精选
九头蛇的安装与使用 世界热议
焦点热门:第二章:数据模型与查询语言
P1344 [USACO4.4] 追查坏牛奶 Pollutant Control (网络流)
MySQL 迁移至 SQLite 问题记录 全球通讯
全球今日报丨【新华500】新华500指数(989001)18日下跌0.14%
当前时讯:最高检发新文:NFT法律属性定调哪般?
天天日报丨黄桃+椰果!林家铺子双色水果罐头8罐仅19.9元
天天头条:比亚迪再掀桌子!新款汉DM-i冠军版上市:18.98万起合资还怎么玩
同事都说买高像素就对了 四款热门高像素全画幅相机推荐-天天百事通
微资讯!HTC U23 Pro发布:性价比这么低的手机不多了
世界热点评!日赚4亿还嫌多?移动联通电信现在和10年前日赚一样多:手机资费下降95%等
百度投资卡车整车研发商载合汽车科技_环球快讯
环球热点![MySQL 如何分析性能]
天天速递!Python从零到壹丨图像增强的顶帽运算和底帽运算
知识拷问:工作站和服务器哪个更适合做CST电磁仿真?|每日观察
今日讯!3万多买钻戒如今只值2000元 网友称还是黄金保值:你会买钻戒吗?
60Hz显示器配120帧显卡是浪费?答案意外_世界即时看
最新资讯:包含多家中国造车新势力!马斯克预言一年内必有车厂倒闭
360 AIGC产品定名360智脑、360鸿图
三星量产12nm DDR5内存:功耗骤降23% 全球新视野
追讨欠款的有效期限是多久?欠钱不还电话不接微信不回怎么办?
ChatGPT 插件,组合后更妙了
快报:零跑汽车在杭州成立动力系统公司,注册资本1亿元
地球母亲怎么了?世界气象组织警告:未来五年全球气温将创新高-热头条
全球最新:知名女演员最新大片引争议 网友惊呼:这花有毒!
用这些C#代码混淆器保护你的代码安全_速递
环球微头条丨港元1个月拆息升至近5个月高 报4.57238厘
215英寸口袋巨幕!雷鸟Air Plus发布:首发2299元
世界快消息!男子在路边花5600元买到战国青铜剑:捐赠给博物馆
《王者荣耀》安琪拉/亚瑟520限定皮肤公布 传说品质-每日聚焦
周星驰担任网飞版《美猴王》执行制作:定档8月18日 大圣外形被吐槽|世界速讯
《权力的游戏》演员称曾被网暴到退网:就因为角色不讨喜
5月18日河北中昌化肥硫酸铵价格动态
世界最资讯丨MongoDB + SpringBoot 的基础CRUD、聚合查询
开源即时通讯IM框架MobileIMSDK的Uniapp端开发快速入门
【世界独家】TimescaleDB VS TDengine:写入性能和查询性能是 TDengine 的 1/6、1/28
世界百事通!夜莺官方文档优化第一弹:手把手教你部署和架构讲解,消灭所有部署失败的 case!干!
直播预告 | 员工在公司体验感UP,原因竟然是这个......
美国债务上限谈判出现曙光 日元价格跌破年内新低
全球热点评!小米Civi 3首发天玑8200 Ultra!小米影像大脑更强了:连拍提速235%
报告称:81%员工不认为其工作可以被AI取代-天天热点
7450MB/s!三星990 Pro旗舰SSD价格腰斩:2TB只要1229元
每日时讯!发条朋友圈就能赚钱?支付宝辟谣:“朋友圈出租”是骗局
头条:魔兽国服关了114天 暴雪选择躺平:工作室脚本泛滥 玩家遭殃