14.Netty框架的C#实战使用

2023-11-09

博客概述

我是java线的工程师,但是技术栈有点全栈的意思。在某次项目中需要用到c#的socket通讯,查询之后惊喜的发现c#也有netty框架。dotnetty,github托管地址:https://github.com/Azure/DotNetty/blob/dev/examples/SecureChat.Client/Program.cs 于是乎开始用netty框架来愉快的实现业务,过程中用到了c#的客户端和服务端,因为语言的差异性,关于同步异步多线程部分踩了不少坑。过程我就不多阐述了,这里贴上代码,有需要的同学可以拿去用。

场景与实现

这次c#的使用场景是WPF。

C#服务器端实现

启动netty服务,作为c#服务器端

  Thread th = new Thread(() =>
            {
                try
                {
                    NettyLuncher.getInstance().Start().Wait();

                }
                catch (AggregateException ee)
                {
                    App.Current.Dispatcher.Invoke(new Action(() =>
                    {
                        MessageBoxX.Info(LanguageUtils.GetCurrentLanuageStrByKey("App.PortOccupy"));
                        System.Environment.Exit(0);
                    }));
                }
            });
            th.Start();

c#的netty启动类,具体的业务handler因为保密的原因就不贴出了。代码里面用了单例的方法。

using DotNetty.Handlers.Logging;
using DotNetty.Handlers.Tls;
using DotNetty.Transport.Bootstrapping;
using DotNetty.Transport.Channels;
using DotNetty.Transport.Channels.Sockets;
using System.Security.Cryptography.X509Certificates;
using spms.protocol;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using DotNetty.Codecs;
using DotNetty.Buffers;

namespace spms.server
{
    public class NettyLuncher
    {
        private volatile static NettyLuncher instance = new NettyLuncher();

        public static NettyLuncher getInstance()
        {
            return instance;
        }
        private NettyLuncher()
        {

        }

        private ManualResetEvent _mainThread = new ManualResetEvent(false);
        public void ShutdownGracefully()
        {
            _mainThread.Set();
        }

        public async Task Start()
        {

            int port = 6860;
            string p = ConfigurationManager.AppSettings["NettyPort"];
            if (p == null || "".Equals(p))
            {
                port = int.Parse(p);
            }
        
            var bossGroup = new MultithreadEventLoopGroup(1);
            var workerGroup = new MultithreadEventLoopGroup();
            try
            {
                var bootstrap = new ServerBootstrap();
                bootstrap
                    .Group(bossGroup, workerGroup) //  
                    .Channel<TcpServerSocketChannel>() // 
                    .Option(ChannelOption.SoBacklog, 100) //  
                    .Handler(new LoggingHandler("SRV-LSTN")) // 
                    .ChildHandler(new ActionChannelInitializer<ISocketChannel>(channel =>
                    { // 
                        IChannelPipeline pipeline = channel.Pipeline;
                      
                         IByteBuffer delimiter = Unpooled.Buffer(); ;
                        delimiter.WriteByte((byte)0x7E);
                        pipeline.AddLast(new DelimiterBasedFrameDecoder(1024, delimiter));
                        pipeline.AddLast(new LoggingHandler("SRV-CONN"));
                        pipeline.AddLast("tcpHandler", new ProtocolHandler());
                    }));

                // bootstrap bind port 
                IChannel boundChannel = await bootstrap.BindAsync(port);
                //线程阻塞在这
               
                _mainThread.WaitOne();
                //关闭服务
                await boundChannel.CloseAsync();
            }
            finally
            {
                await Task.WhenAll(
                    bossGroup.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)),
                    workerGroup.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)));
            }
        }
    }
}

C#客户端的写法

app里面的随机启动代码

  Thread hbth = new Thread(() =>
            {     
                    HeartbeatClient heartbeatClient = new HeartbeatClient();
                    while (true)
                    {
                        try
                        {
                            BodyStrongMessage bodyStrongMessage = new BodyStrongMessage
                            {
                                MessageType = BodyStrongMessage.Types.MessageType.Heaerbeatreq,
                                //可能为null
                                HeartbeatRequest = TcpHeartBeatUtils.GetHeartBeatByCurrent()
                            };

                       
                        HeartbeatClient.RunClientAsync(bodyStrongMessage).Wait();
                   
                        

                    }
                     catch (Exception exception)
                        {
                            //exception.Message();
                            TcpHeartBeatUtils.WriteLogFile("连接云平台线程发送失败"+ exception.StackTrace);
                        }
                        finally {
                            Thread.Sleep(5000);
                        }
                    }
 
            });
            hbth.Start();

netty作为客户端的具体实现代码,主要用于心跳,目前的代码写法有弊端,以后有空会优化。

using Com.Bdl.Proto;
using DotNetty.Codecs.Protobuf;
using DotNetty.Transport.Bootstrapping;
using DotNetty.Transport.Channels;
using DotNetty.Transport.Channels.Sockets;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace spms.heartbeat
{
    public class HeartbeatClient
    {

        public static async Task RunClientAsync(BodyStrongMessage msg)
        {        
            var group = new MultithreadEventLoopGroup();
            try
            {
                var bootstrap = new Bootstrap();
                bootstrap
                    .Group(group)
                    .Channel<TcpSocketChannel>()
                    .Option(ChannelOption.TcpNodelay, true)
                    .Handler(new ActionChannelInitializer<ISocketChannel>(channel =>
                    { 
                        IChannelPipeline pipeline = channel.Pipeline;
                        pipeline.AddLast("frameDecoder", new ProtobufVarint32FrameDecoder());
                        pipeline.AddLast("decoder", new ProtobufDecoder(BodyStrongMessage.Parser));
                        pipeline.AddLast("frameEncoder", new ProtobufVarint32LengthFieldPrepender());
                        pipeline.AddLast("encoder", new ProtobufEncoder());
                        pipeline.AddLast("tcpHandler", new HeartbeatHandler());

                    }));

                IChannel bootstrapChannel = await bootstrap.ConnectAsync(new IPEndPoint(IPAddress.Parse("192.168.1.109"), 60000));

                await bootstrapChannel.WriteAndFlushAsync(msg);
                //Console.ReadLine();

                await bootstrapChannel.CloseAsync();
            }
            finally
            {
                group.ShutdownGracefullyAsync().Wait(1000);
            }
        }
    }
  
}

优化之后的netty客户端的写法,这一版本就对上面那个传一次创建一次的写法做了优化。经过测试没有问题。

using System;
using System.Threading;
using System.Threading.Tasks;
using AISports.HeartBeat;
using Com.Bdl.Proto;
using DotNetty.Codecs.Protobuf;
using DotNetty.Transport.Bootstrapping;
using DotNetty.Transport.Channels;
using DotNetty.Transport.Channels.Sockets;

namespace AISports.HeartBeat
{
    public delegate void ReceiveMessageEvent(object message);


    public class ProtoBufSocket
    {
        public event ReceiveMessageEvent ReceiveMessage;

        private AutoResetEvent ChannelInitilizedEvent = new AutoResetEvent(false);
        private Bootstrap SocketBootstrap = new Bootstrap();
        private MultithreadEventLoopGroup WorkGroup = new MultithreadEventLoopGroup();
        private volatile bool Connected = false;
        private IChannel Channel;

        public ProtoBufSocket()
        {
            InitBootstrap();
        }

        private void InitBootstrap()
        {
            SocketBootstrap.Group(WorkGroup)
                .Channel<TcpSocketChannel>()
                .Option(ChannelOption.TcpNodelay, true)
                .Option(ChannelOption.SoKeepalive, true)
                .Handler(new ActionChannelInitializer<ISocketChannel>(channel =>
                {
                    IChannelPipeline pipeline = channel.Pipeline;
                    pipeline.AddLast("frameDecoder", new ProtobufVarint32FrameDecoder());
                    pipeline.AddLast("decoder", new ProtobufDecoder(BodyStrongMessage.Parser));
                    pipeline.AddLast("frameEncoder", new ProtobufVarint32LengthFieldPrepender());
                    pipeline.AddLast("encoder", new ProtobufEncoder());
                    pipeline.AddLast("tcpHandler", new HeartbeatHandler());
                }));
        }


        public void Connect()
        {
            //var thread = new Thread(new ThreadStart(DoConnect().Wait));
            //thread.Start();
            DoConnect().Wait();
        }
        public void Disconnect()
        {
            WorkGroup.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1));
        }

        public void SendMessage(object message)
        {
            if (!Connected)
                //Connected = ChannelInitilizedEvent.WaitOne();
                Connect();

            Channel.WriteAndFlushAsync(message);
        }

        private async Task DoConnect()
        {
            Connected = false;
            var connected = false;
            do
            {
                try
                {
                    var clientChannel = await SocketBootstrap.ConnectAsync("192.168.43.95", 60000);
                    Channel = clientChannel;
                    ChannelInitilizedEvent.Set();
                    connected = true;
                }
                catch (Exception /*ce*/)
                {
                    //Console.WriteLine(ce.StackTrace);
                    Console.WriteLine("Reconnect server after 5 seconds...");
                    Thread.Sleep(5000);
                }
            } while (!connected);
        }

    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

14.Netty框架的C#实战使用 的相关文章

  • libevent(7)libevent中的事件event

    一 事件状态 libevent有4种事件状态 分别是 initialized pending active persistent 这4种状态的转换关系如下 1 已初始化 initialized 对应图中的non pending状态 表示事件
  • 网络编程——TFTP协议(基于UDP)

    目录 1 tftp协议概述 2 tftp下载模型 3 tftp协议分析 代码 1 tftp协议概述 简单文件传输协议 适用于在网络上进行文件传输的一套标准协议 使用UDP传输 特点 是应用层协议 基于UDP协议实现 数据传输模式 octet
  • windows网络编程-结构体说明

    1 sockaddr in struct sockaddr in short sin family u short sin port 端口 struct in addr sin addr IP地址 long类型 4字节 char sin z
  • 网络分层模型

    OSI七层模型 物数网传会表应 物理层 主要定义物理设备标准 如网线的接口类型 光纤的接口类型 各种传输介质的传输速率等 它的主要作用是传输比特流 就是由1 0转化为电流强弱来进行传输 到达目的地后再转化为1 0 也就是我们常说的数模转换与
  • C、C++中对json格式数据的解析和封装

    C 首先需要调库 include
  • 【网络编程·应用层】https协议——加密与窃密的攻防战

    需要云服务器等云产品来学习Linux的同学可以移步 gt 腾讯云 lt gt 阿里云 lt gt 华为云 lt 官网 轻量型云服务器低至112元 年 新用户首次下单享超低折扣 目录 一 https协议的介绍 二 加密和解密 1 加密和解密的
  • libevent(6)windows上使用iocp网络模型

    windows操作系统上不能使用epoll模型 只能使用iocp网络模型 这里我把怎么在windows上使用iocp的代码直接贴上 include
  • gethostbyname()函数详解

    基本概念 gethostbyname 函数主要作用 用域名或者主机名获取地址 操作系统提供的库函数 以下的讨论基于linux环境 域名系统 Domain Name System DNS 主要用于主机名字与IP地址之间的映射 每个组织机构往往
  • Unix网络编程5种IO模型

    IO模型 用一幅图表示所支持的I O模型 纵向维度是 阻塞 Blocking 非阻塞 Non blocking 横向维度是 同步 异步 总结起来是四种模型 同步阻塞 同步非阻塞 异步阻塞 异步非阻塞 Unix网络编程 中划分出了 第五种 模
  • 基于Linux用C语言实现TCP/UDP图片和文件传输(socket)

    目录 一 TCP实现 1 服务端 2 客户端 二 UDP实现 1 服务端 2 客户端 一 TCP实现 传输控制协议 TCP Transmission Control Protocol 是为了在不可靠的互联网络上提供可靠的端到端字节流而专门设
  • TCP的粘包问题

    TCP transport control protocol 传输控制协议 是面向连接的 面向流的 提供高可靠性服务 收发两端 客户端和服务器端 都要有一一成对的socket 因此 发送端为了将多个发往接收端的包 更有效的发到对方 使用了优
  • JUC学习系列六(计数器 CountDownLatch)

    一个同步辅助类 在完成一组正在其他线程中执行的操作之前 它允许一个或多个线程一直等待 用给定的计数 初始化 CountDownLatch 由于调用了 countDown 方法 所以在当前计数到达零之前 await 方法会一直受阻塞 之后 会
  • 【网络编程】网络编程知识点总结

    文章目录 UDP也需要端口号 基于TCP的socket通信中 简易服务端的六步依次为 基于TCP的socket通信中 简易客户端的四步依次为 介绍一下在linux环境下 服务器这六步的使用到的一些函数 参数 返回值类型等 介绍一下在linu
  • 进程间通信之共享内存分析

    零拷贝技术 https strikefreedom top linux io and zero copy 一 内存映射和共享内存的区别 1 1 内存映射之mmap函数 将一个文件或者其它对象映射到进程的地址空间 实现文件磁盘地址和进程虚拟地
  • HTTP与HTTPS的区别,HTTPS的工作原理及优缺点

    为什么要有HTTPS 超文本传输协议HTTP协议被用于在web服务器和网站服务器之间传递消息 HTTP协议以明文方式发送内容 不提供任何方式的数据加密 如果攻击者截取了web浏览器和网站服务器之间的传输报文 就可以直接读懂其中的信息 因此
  • day075:XML的约束:DTD约束文档、DTD约束文档的三种引入方法、DTD语法规则

    目录 一 DTD约束 1 什么是DTD约束 2 创建DTD约束文档的步骤 3 代码示例 4 引入DTD约束文档的三种方法 1 引入本地DTD约束文档 2 在xml文件内部引入 3 从网络引入dtd文件 二 DTD语法规则 DTD定义元素 标
  • Muduo库源码剖析(十)——总结

    Muduo网络库的核心代码模块 Channel 封装fd的对应事件变化情况 和关注事件 fd events revents callbacks 两种channel listenfd acceptorChannel connfd connec
  • 安装配置qt_eventdispatcher_libevent

    QT默认的是使用select模型的 这种轮询方式非常慢 在高并发连接 我们需要epoll才能发挥linux服务器的性能 安装qt eventdispatcher libevent 下载安装包后 解压 找到src目录 用Qt打开pro工程 然
  • C++针对ZeroMQ库的选择

    介绍 ZeroMQ 也称为0MQ或 MQ 是一个高性能 低延迟的消息队列库 它为分布式和并发应用程序提供了简洁 高效的通信机制 它是一个开源的库 支持多种编程语言 包括C 和操作系统 ZeroMQ通过使用套接字抽象来实现消息传递 使得它易于
  • mongos、nanomsg、zeroMQ简述和go-mongos使用实例

    mongos nanomsg zeroMQ简述和go mongos使用实例 文章目录 mongos nanomsg zeroMQ简述和go mongos使用实例 1 mongos nanomsg简述 2 zeroMQ nanomsg和可扩展

随机推荐

  • 低成本副业:开发小程序商城攻略

    随着互联网的普及和电子商务的兴起 越来越多的人选择做点副业 其中开发小程序商城是一个不错的选择 相比传统的实体店 小程序商城的成本更低 而且门槛更低 可以让更多的人参与到副业中来 那么 如何开发自己的小程序商城呢 下面为大家介绍步骤和技巧
  • STM32中遇到的问题--关于串口的一些常见问题

    在单片机的开发过程中 最常用的外设就是串口了 是用来进行bug纠错 log输出的常用工具 也是用来与外部通讯的常见协议之一 但是在使用串口的过程中难免会遇到一些问题 下面就我在工作遇到的一些问题做了一些记录 与大家分享 其实也是为了自己在以
  • [云原生专题-39]:K8S - 核心概念 - 存储抽象- pod配置文件的挂载ConfigMap

    作者主页 文火冰糖的硅基工坊 文火冰糖 王文兵 的博客 文火冰糖的硅基工坊 CSDN博客 本文网址 https blog csdn net HiWangWenBing article details 122856681 目录 前言 第1章
  • 安卓逆向入门指南:应用分析与反编译

    安卓逆向入门指南 应用分析与反编译 概述 简要介绍安卓逆向工程的基本概念和背景 解释逆向工程的目的和重要性 以及在安全审计和应用研究中的应用 应用分析 安卓应用文件结构的解析 介绍APK文件的结构 包括AndroidManifest xml
  • c#中new 后面大括号

    C new一个对象的时候 后面的参数不是用小括号吗 下面的大括号是怎么回事 不是数据为什么会用大括号 BarcodeWriter barcodeWriter new BarcodeWriter Format ZXing BarcodeFor
  • jmap、jstat、jinfo、jstack命令详解

    jmap jmap histo pid gt log txt 此命令可以用来查看内存信息 实例个数以及占用内存大小 num 序号 instances 实例数量 bytes 占用空间大小 class name 类名称 C is a char
  • Windows中.exe程序的启动过程和C/C++运行时库<转载>

    很是受益 Windows中 exe程序的启动过程和C C 运行时库 lt 转载 gt Windows系统中 exe后缀的文件一般可以双击运行 编程时 编译出来的最终结果一般也表现为一个exe程序和其他的为程序执行提供支持的dll 我们双击一
  • Unity3d-简单AR游戏

    Unity3d 简单AR游戏 一 图片识别与建模 Vufria模块的导入 首先是安装Vuforia 模块 2017版本后的可以直接使用Unity Hub安装 安装完成后可以直接在软件中使用 然后在菜单目录的GameObject gt Vuf
  • 利用docx4j word转pdf

    依赖
  • 不能导入当前目录下的py模块,不能导入自己写的包

    遇到一个很奇怪的问题 在jupyter里面 明明这个包就在当前目录下就是不能倒入 后来 发现os getcwd 返回的也不是当前文件所在目录 真是奇哉怪也 然后我在终端cd进去我要运行代码的目录 然后在 jupoyter notebook
  • 【计算机考研】从二本到浙大

    报名志愿 浙大 计算机科学与技术学院 软件工程专业 初试成绩 分数不高 大佬轻喷 以下学习方法仅供参考 小tip 放在前头 1 不要照搬别人的学习方案 马克思主义要中国化 学习也要个人化 学习是很私人的事情 一定要找到最适合自己的学习作息和
  • 关于IDEA中tomcat启动控制台乱码(server Tomcat Localhost Log Tomcat Catalina Log乱码)问题

    之前在网上查了好多 但好多都是乱改一通 没有实际效果 经过自己的几次试验后 终于找到了原因 希望可以帮助大家解决问题 少走些弯路 具体解释如下 在这之前说下 tomcat安装目录中 conf文件夹中的logging properties文件
  • linux vim配置

    vimrc config vim 配置 没有vimrc就之间创建新的 vi vimrc set nu 设置显示行号 set tabstop 4 shiftwidth 4 softtabstop 4 tab 等于四个空格 set expand
  • org.dom4j.DocumentException: null Nested exception: null解决

    org dom4j DocumentException null Nested exception null at org dom4j io SAXReader read SAXReader java 484 at org dom4j io
  • 【SpringCloud实战开发总结】

    Vue开发总结 1 Vue 开启Watch监听 2 on blur 3 disabled 4 InputNumber标签中的 max和 min 5 Select标签用于模糊查询 6 强制渲染的三种方法 7 增加下拉框宽度 8 vue前端校验
  • DHT11温湿度传感器编程详解

    一 DHT11介绍 DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器 采用专用的数字模块采集技术和温湿度传感技术 无需复杂的电路处理 传感器包括一个电阻式感湿元件和一个NTC测温元件 并与一个高性能8位单片机相连接
  • D3D初学入门一(配置开发环境及绘制D3D窗口)

    最近一直接触的都是C 的东东 好久没写C 代码了 怕手生忘记了 打算写写C 的代码 写什么好呢 想来想去 以前的工作学过接触了些OpenGL 那我就学习一下D3D吧 原以为D3D的中文入门资料会很多的 结果找了半天也没找到合适的 哎 随便将
  • struts2+hibernate+spring配置详解

    struts2 hibernate spring配置详解 struts2 hibernate spring配置详解 哎 当初一个人做好难 现在终于弄好了 希望自学这个的能少走些弯路 以下是自己配置的案例 注意 要想明白的比较好 请下载这个配
  • java字符串是否相等的三种判断方法

    1 比较的是否是同一对象 eg String str1 abc str2 abc if str1 str2 结果为true 因为在java中字符串的值是不可改变的 相同的字符串在内存中只会存 一份 所以a和b指向的是同一个对象 eg Str
  • 14.Netty框架的C#实战使用

    文章目录 博客概述 场景与实现 C 服务器端实现 C 客户端的写法 博客概述 我是java线的工程师 但是技术栈有点全栈的意思 在某次项目中需要用到c 的socket通讯 查询之后惊喜的发现c 也有netty框架 dotnetty gith