C# DotNetty客户端,包含心跳发送,断线重连机制

1.新建MessageBean消息类型类,也可以不用,看自己需要

public enum MsgType { STATUS_CONNECT_ERROR, STATUS_CONNECT_SUCCESS, STATUS_CONNECT_CLOSED, STATUC_CONNECT_RECONNECT }public class MessageBean
{/*** 消息类型*/private MsgType type;/*** 消息数据*/private Object msg;public MessageBean(MsgType type,Object msg){this.type = type;this.msg = msg;}public Object getMsg(){return msg;}public void setMsg(Object msg){this.msg = msg;}public void setType(MsgType type){this.type = type;}public MsgType getType(){return type;}public override string ToString(){return "MsgBean{" +"type=" + type +", msg=" + msg +'}';}
}

2.新建DotNettyClientHandler类,用于接收服务端消息

public class DotNettyClientHandler : FlowControlHandler
{/// <param name="ctx"></param>/// <param name="msg"></param>private DotNettyListener listener;private static String strMsg; public DotNettyClientHandler(DotNettyListener listener){this.listener = listener;}public override void ChannelActive(IChannelHandlerContext context){Console.WriteLine("==================ChannelActive======================");if (null != listener){listener.onServiceStatusConnectChanged(new MessageBean(MsgType.STATUS_CONNECT_SUCCESS, null));}}public override void ChannelInactive(IChannelHandlerContext context){base.ChannelInactive(context);//掉线了Console.WriteLine("===============ChannelInactive==============");if (null != listener){listener.onServiceStatusConnectChanged(new MessageBean(MsgType.STATUS_CONNECT_CLOSED, null));}DotNettyClient.getInstance(listener).start();}public override void ChannelRead(IChannelHandlerContext context, object msg){Console.WriteLine("===============ChannelRead==============");IByteBuffer byteBuffer = msg as IByteBuffer;strMsg += byteBuffer.ToString(Encoding.UTF8);if (byteBuffer != null){Console.WriteLine("byteBuffer:" + strMsg);if (strMsg.StartsWith("{") && strMsg.EndsWith("}")){listener.onMessageResponse(strMsg);strMsg = null;}}else {Console.WriteLine("---------null---------- ");}//context.WriteAsync(msg);}public override void ChannelReadComplete(IChannelHandlerContext context){Console.WriteLine("===============ChannelReadComplete==============");context.Flush();}public override void UserEventTriggered(IChannelHandlerContext context, object evt){Console.WriteLine("----------------UserEventTriggered----------------");base.UserEventTriggered(context, evt);if (evt is IdleStateEvent){var e = evt as IdleStateEvent;switch (e.State){//长期没收到服务器推送数据/**case IdleState.ReaderIdle:{//可以重新连接if (!context.Channel.Active)context.ConnectAsync(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9997));}break;//长期未向服务器发送数据case IdleState.WriterIdle:{//发送心跳包byte[] messageBytes = Encoding.UTF8.GetBytes("heartbeat");context.WriteAndFlushAsync(messageBytes);}break;**///Allcase IdleState.AllIdle:{//发送心跳包}break;}}}public override void ExceptionCaught(IChannelHandlerContext context, Exception exception){Console.WriteLine("===============ExceptionCaught==============");Console.WriteLine(exception);context.CloseAsync();if (null != listener){listener.onServiceStatusConnectChanged(new MessageBean(MsgType.STATUS_CONNECT_ERROR, exception.Message));}}
}

3.新建DotNettyClient类,管理DotNetty连接,消息发送

public interface DotNettyListener
{/*** 当接收到系统消息*/void onMessageResponse(Object msg);/*** 当连接状态发生变化时调用*/void onServiceStatusConnectChanged(MessageBean msg);
}
public class DotNettyClient
{#region Instancepublic IChannel clientChannel;public String ip = "127.0.0.1";//ippublic int port = 9997;//端口private DotNettyListener listener;//写的接口用来接收服务端返回的值private static DotNettyClient instance;public static DotNettyClient getInstance(DotNettyListener listener) {if (instance == null) {instance = new DotNettyClient();}instance.setListener(listener);return instance;}private DotNettyClient(){ }#endregionprivate ManualResetEvent ClosingArrivedEvent = new ManualResetEvent(false);public void start(){try{Task.Run(() => runClientAsync(ip,port));}catch (Exception exception){Console.WriteLine(exception.StackTrace);}}public async Task runClientAsync(String ip,int host){var group = new MultithreadEventLoopGroup();X509Certificate2 cert = null;string targetHost = null;try{var bootstrap = new Bootstrap();bootstrap.Group(group).Channel<TcpSocketChannel>().Option(ChannelOption.TcpNodelay, true)//.Option(ChannelOption.ConnectTimeout, new TimeSpan(0, 0, 0, 0, args.ConnectTimeout)).Handler(new ActionChannelInitializer<ISocketChannel>(channel =>{IChannelPipeline pipeline = channel.Pipeline;pipeline.AddLast(new StringEncoder(Encoding.UTF8));//pipeline.AddLast(new StringDecoder(Encoding.UTF8));pipeline.AddLast(new IdleStateHandler(0, 0, 100));pipeline.AddLast(new DotNettyClientHandler(listener));//定义Handler类及名称                }));clientChannel = await bootstrap.ConnectAsync(ip,port);ClosingArrivedEvent.Reset();ClosingArrivedEvent.WaitOne();await clientChannel.CloseAsync();}catch (Exception exp){//MainWindow.SetText("Client connection failed");Console.WriteLine(exp.ToString());Console.WriteLine(exp.StackTrace);}finally{//await group.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1));reConnectServer();}}//断线重连private void reConnectServer(){Console.WriteLine("=================reConnectServer===================");if (null != listener) {listener.onServiceStatusConnectChanged(new MessageBean(MsgType.STATUC_CONNECT_RECONNECT, null));}try{Thread.Sleep(5000);start();}catch (Exception e){}}public bool SendMessage(string message){if (clientChannel != null && clientChannel.Open){clientChannel.WriteAndFlushAsync(message);Console.WriteLine("Sent message to server: " + message);return true;}return false;}public void disconnect() {Console.WriteLine("============disconnect==============");//await channel.CloseAsync();clientChannel.CloseAsync();}public void setListener(DotNettyListener listener){this.listener = listener;}
}

4.使用DotNetty

public partial class Form1 : Form, DotNettyListener
{public Form1(){InitializeComponent();}public void onMessageResponse(object msg){Console.WriteLine(msg);}public void onServiceStatusConnectChanged(MessageBean msg){Console.WriteLine("type = "+msg.getType()+",msg = "+msg.getMsg());}private void simpleButton1_Click(object sender, EventArgs e){DotNettyClient client = DotNettyClient.getInstance(this);client.start();Thread.Sleep(5000);client.SendMessage("12345");}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/882063.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

visio导出pdf公式变形问题杂谈

其实不会变形。 我自己的情况是直接用edge PDF阅读器打开pdf看到的是公式有变形&#xff08;常见是字体、形状变了&#xff09;&#xff0c;但换一个pdf阅读器如adobe的就是正常的了 不过大家一般是用edge pdf阅读器直接打开查看&#xff0c;所以通过visio打印的方式导出pdf可…

若依框架中spring security的完整认证流程,及其如何使用自定义用户表进行登录认证,学会轻松实现二开,嘎嘎赚块乾

1&#xff09;熟悉之前的SysUser登录流程 过滤器链验证配置 这里security过滤器链增加了前置过滤器链jwtFilter 该过滤器为我们自定义的&#xff0c;每次请求都会经过jwt验证 ok我们按ctrl alt B跳转过去来看下 首先会获取登录用户LoginUser 内部通过header键&#xff0c;获…

第十二章 RabbitMQ之失败消息处理策略

目录 一、引言 二、RepublishMessageRecoverer 实现 2.1. 实现步骤 2.2. 实现代码 2.2.1. 异常交换机队列回收期配置类 2.2.2. 常规交换机队列配置类 2.2.3. 消费者代码 2.2.4. 消费者yml配置 2.2.5. 生产者代码 2.2.6. 生产者yml配置 2.2.7. 运行效果 一、引言 …

重新定义自动驾驶的动态视觉?谷歌提出几何优先的动态场景方法MonST3R

导读&#xff1a; 本文引入了Motion DUSt3R (MonST3R)&#xff0c;这是一种几何优先的动态场景方法&#xff0c;它以点图的形式直接估计几何形状。相比以前的工作&#xff0c;MonST3R具有如下关键优势&#xff1a; 增强的稳健性&#xff0c;特别是在具有挑战性的场景中&#xf…

【二刷hot-100】day2

目录 1.无重复字符的最长子串 2.找到字符串中所有字母异位词 3.和为 K 的子数组 4.滑动窗口最大值 1.无重复字符的最长子串 class Solution {public int lengthOfLongestSubstring(String s) {Map<Character,Integer> dict new HashMap<>();int ret0;int i-1;for…

从一致性哈希算法带来的分布式系统设计思考

引言 在分布式系统中&#xff0c;数据存储和访问的均匀性、高可用性及可扩展性至关重要。一致性哈希算法&#xff08;Consistent Hashing&#xff09;以其优秀的数据分布特性&#xff0c;广泛应用于缓存、负载均衡和数据库分片等领域&#xff0c;有效提升了系统的稳定性和灵活…

uniapp onPageScroll

子组件有onPageScroll, 首页也要引入onPageScroll, eg: 主页面 sell/detail/index 《子组件》 <script setup> 引入onPageScroll </script> 组件&#xff1a; 引入onPageScroll 别人的比较

如果使用 Iptables 配置端口转发 ?

现实生活中&#xff0c;港口转发就像在一个大型公寓大楼里告诉送货司机该去哪里。通常情况下&#xff0c;该建筑群的正门是不对外开放的。但如果里面有人想要快递&#xff0c;他们可以告诉保安让司机进来&#xff0c;并指引他们到特定的公寓。 类似地&#xff0c;在计算机网络…

jeecg3版本的vue,离线启动

jeecg的vue2版本已经停止维护&#xff0c;所以只能用vue3的版本。3版本中使用的是pnpm&#xff08;npm的增强版本&#xff09;下载依赖。使用pnpm安装的node_modules&#xff0c;不能直接复制到离线主机中&#xff08;因为在 pnpm安装过程中&#xff0c;会给依赖的配置文件写死…

Elasticsearch 入门

ES 概述 ES 是一个开源的高扩展的分布式全文搜索引擎。 倒排索引 环境准备 Elasticsearch 官方地址&#xff1a;https://www.elastic.co/cn/ 下载地址&#xff1a; 注意&#xff1a;9300 端口为 Elasticsearch 集群间组件的通信端口&#xff0c;9200 端口为浏览器访问的 h…

【赵渝强老师】K8s中Deployment控制器与StatefulSet控制器的区别

一、K8s的Deployment与StatefulSets 在K8s中&#xff0c;Deployment将Pod部署成无状态的应用程序&#xff0c;它只关心Pod的数量、Pod更新方式、使用的镜像和资源限制等。由于是无状态的管理方式&#xff0c;因此Deployment中没有角色和顺序的概念&#xff0c;换句话说&#xf…

vue项目页面白边如何解决

这是出现白边的页面 原因是vue项目创建时在main.js下它引入了刚开始提供的main.css全局设置 直接把该设置注释掉即可&#xff0c; 然后在App.vue中添加如下style&#xff0c;就大功告成了

2025推荐选题|微信小程序实现经济新闻资讯

作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、多年校企合作经验&#xff0c;被多个学校常年聘为校外企业导师&#xff0c;指导学生毕业设计并参与学生毕业答辩指导&#xff0c;…

2.stm32 GPIO输出

GPIO简介 GPIO&#xff08;General Purpose Input Output&#xff09;通用输入输出口 可配置为8种输入输出模式 引脚电平&#xff1a;0V~3.3V&#xff0c;部分引脚可容忍5V 输出模式下可控制端口输出高低电平&#xff0c;用以驱动LED、控制蜂鸣器、模拟通信协议输出时序等 …

tensorflow入门案例手写数字识别人工智能界的helloworld项目落地1

参考 https://tensorflow.google.cn/?hlzh-cn https://tensorflow.google.cn/tutorials/keras/classification?hlzh-cn 项目资源 https://download.csdn.net/download/AnalogElectronic/89872174 文章目录 一、案例学习1、导入测试和训练数据集&#xff0c;定义模型&#xff…

【R语言】随机森林+相关性热图组合图

数据概况文末有获取方式 随机森林部分 #调用R包 library(randomForest) library(rfPermute) library(ggplot2) library(psych) library(reshape2) library(patchwork) library(reshape2) library(RColorBrewer) ​ ​ #读取数据 df<-read.csv("F:\\EXCEL-元数据\\2020…

深度学习之残差网络ResNet

文章目录 1. 残差网络定义2. 数学基础函数类3. 残差块4.ResNet模型5.训练模型6.小结 1. 残差网络定义 随着我们设计的网络越来越深&#xff0c;深刻理解“新添加的层如何提升神经网络的性能”变得至关重要。更重要的是设计网络的能力。在这种网络中&#xff0c;添加层会使得网…

2010年国赛高教杯数学建模A题储油罐的变位识别与罐容表标定解题全过程文档及程序

2010年国赛高教杯数学建模 A题 储油罐的变位识别与罐容表标定 通常加油站都有若干个储存燃油的地下储油罐&#xff0c;并且一般都有与之配套的“油位计量管理系统”&#xff0c;采用流量计和油位计来测量进/出油量与罐内油位高度等数据&#xff0c;通过预先标定的罐容表&#…

JDBC的学习

一、JDBC DriverManager 二、JDBC connection 三、 JDBC Statement 1.DML 2.DDL 四、JDBC ResultSet 五、JDBC PreparedStatement

30.第二阶段x86游戏实战2-遍历周围-C++遍历二叉树(玩家角色基址)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 本人写的内容纯属胡编乱造&#xff0c;全都是合成造假&#xff0c;仅仅只是为了娱乐&#xff0c;请不要…