记录

写本系列文章的目的主要是记录调研的成果。


一、Netty是什么

Netty 是一款用于创建高性能网络应用程序的高级框架。

Netty 是一款异步的事件驱动的网络应用程序框架,支持快速地开发可维护的高性能的面向协议的服务器和客户端

二、DotNetty是什么

DotNetty是微软的Azure团队仿造Netty编写的网络应用程序框架。

三、BIO和NIO

3.1 以上图就是代表BIO的流程

  1. 建立连接要阻塞线程,读取数据要阻塞线程
  2. 如果要管理多个客户端,就需要为每个客户端建立不同的线程
  3. 会有大量的线程在休眠状态,等待接收数据,资源浪费
  4. 每个线程都要占用系统资源
  5. 线程的切换很耗费系统资源

3.2 以上图就是NIO的流程

Netty 的 IO 聚合了多路复用器 Selector,可以同时并发处理成百上千个客户端连接。当线程从某客户端 Socket 通道进行读写数据时,若没有数据可用时,该线程可以进行其他任务。线程通常将非阻塞 IO 的空闲时间用于在其他通道上执行 IO 操作,所以单独的线程可以管理多个输入和输出通道。由于读写操作都是非阻塞的,这就可以充分提升 IO 线程的运行效率,避免由于频繁 I/O 阻塞导致的线程挂起,减少了线程数量导致的资源占用,减少了线程切换导致的资源消耗。

四、使用步骤

1.引入库

版本:.netframework4.6 ,DotNetty 0.6.0

引入:DotNetty.Buffers, DotNetty.Codecs ,  Dotnetty.Codecs.Mqtt ,DotNetty.Common , DotNetty.Handlers ,DotNetty.Transport

2.服务端

服务端代码如下:


DiscardServerHandler dis= new DiscardServerHandler()
// 主工作线程组,设置为1个线程
var bossGroup = new MultithreadEventLoopGroup(1);
// 工作线程组,默认为内核数*2的线程数
var workerGroup = new MultithreadEventLoopGroup();//声明一个服务端Bootstrap,每个Netty服务端程序,都由ServerBootstrap控制,
//通过链式的方式组装需要的参数
var bootstrap = new ServerBootstrap();bootstrap.Group(bossGroup, workerGroup) // 设置主和工作线程组.Channel<TcpServerSocketChannel>() // 设置通道模式为TcpSocket.Option(ChannelOption.SoBacklog, 100) // 设置网络IO参数等,这里可以设置很多参数,当然你对网络调优和参数设置非常了解的话,你可以设置,或者就用默认参数吧.Option(ChannelOption.SoKeepalive, true)//保持连接//.Option(ChannelOption.RcvbufAllocator, new FixedRecvByteBufAllocator(4000)).ChildHandler(new ActionChannelInitializer<ISocketChannel>(channel =>{byte[] messageBytes = Encoding.UTF8.GetBytes("^$end");IByteBuffer initialMessage=Unpooled.Buffer(messageBytes.Length);initialMessage.WriteBytes(messageBytes);//工作线程连接器 是设置了一个管道,服务端主线程所有接收到的信息都会通过这个管道一层层往下传输//同时所有出栈的消息 也要这个管道的所有处理器进行一步步处理IChannelPipeline pipeline = channel.Pipeline;pipeline.AddLast(new DelimiterBasedFrameDecoder(40000, initialMessage));//格式规则:每条数据必须以后缀名以^$end格式发送pipeline.AddLast(new CommonServerDecoder());pipeline.AddLast(new CommonServerEncoder());pipeline.AddLast(new IdleStateHandler(0, 0, 180));//业务handler ,这里是实际处理业务的Handlerpipeline.AddLast(dis);}));// bootstrap绑定到指定端口的行为 就是服务端启动服务,同样的Serverbootstrap可以bind到多个端口
IChannel boundChannel = await bootstrap.BindAsync(3399);

3.客户端

客户端示例如下:

 private MultithreadEventLoopGroup group;private IChannel clientChannel;group = new MultithreadEventLoopGroup();var bootstrap = new Bootstrap();bootstrap.Group(group).Channel<TcpSocketChannel>().Option(ChannelOption.TcpNodelay, true)//.Option(ChannelOption.RcvbufAllocator, new FixedRecvByteBufAllocator(40000)) .Handler(new ActionChannelInitializer<ISocketChannel>(c =>{byte[] messageBytes = Encoding.UTF8.GetBytes("^$end");IByteBuffer initialMessage = Unpooled.Buffer(messageBytes.Length);initialMessage.WriteBytes(messageBytes);NettyClientHand nettyClientHand = new NettyClientHand();IChannelPipeline pipeline = c.Pipeline;pipeline.AddLast(new DelimiterBasedFrameDecoder(40000, initialMessage));pipeline.AddLast(new IdleStateHandler(0, 0, 180));pipeline.AddLast(new ClientDecoder());pipeline.AddLast(new ClientEncoder());pipeline.AddLast(nettyClientHand);}));clientChannel = await bootstrap.ConnectAsync(new IPEndPoint(ip, port));

4.粘包和拆包

产生粘包和拆包问题的主要原因是在发送TCP数据的时候,底层会有一个缓冲区,例如1024个字节大小,如果一次请求发送的数据量比较小,没达到缓冲区大小,TCP则会将多个请求合并为同一个请求进行发送,这就形成了粘包问题;如果一次请求发送的数据量比较大,超过了缓冲区大小,TCP就会将其拆分为多次发送,这就是拆包,也就是将一个大的包拆分为多个小包进行发送。

5.粘包和拆包解决方案

1.FixedLengthFrameDecoder :对于使用固定长度的粘包和拆包场景

2.LineBasedFrameDecoder与DelimiterBasedFrameDecoder: 这里LineBasedFrameDecoder的作用主要是通过换行符,即\n或者\r\n对数据进行处理;而DelimiterBasedFrameDecoder的作用则是通过用户指定的分隔符对数据进行粘包和拆包处理

3.LengthFieldBasedFrameDecoder与LengthFieldPrepender:LengthFieldBasedFrameDecoder与LengthFieldPrepender需要配合起来使用,其实本质上来讲,这两者一个是解码,一个是编码的关系。它们处理粘拆包的主要思想是在生成的数据包中添加一个长度字段,用于记录当前数据包的长度。LengthFieldBasedFrameDecoder会按照参数指定的包长度偏移量数据对接收到的数据进行解码,从而得到目标消息体数据;而LengthFieldPrepender则会在响应的数据前面添加指定的字节数据,这个字节数据中保存了当前消息体的整体字节数据长度。

4.LengthFieldBasedFrameDecoder和LengthFieldPrepender:自定义编码器

以上使用第二种分隔符对数据进行粘包 和拆包处理。如果客户端发送消息后缀没有用分隔符,服务端就不会接收。

6.编码和解码

1.服务端CommonServerDecoder解码类代码如下

class CommonServerDecoder: ByteToMessageDecoder{protected override void Decode(IChannelHandlerContext context, IByteBuffer input, List<object> output){byte[] array = new byte[input.ReadableBytes];input.GetBytes(input.ReaderIndex, array, 0, input.ReadableBytes);input.Clear();output.Add(array);}}

2.服务端CommonServerEncoder编码类代码如下

class CommonServerEncoder : MessageToByteEncoder<string>{protected override void Encode(IChannelHandlerContext context, string message, IByteBuffer output){byte[] messageBytes = Encoding.UTF8.GetBytes(message);IByteBuffer initialMessage = Unpooled.Buffer(messageBytes.Length);initialMessage.WriteBytes(messageBytes);output.WriteBytes(initialMessage);}}

3.客户端ClientDecoder编码类代码如下

 class ClientDecoder : ByteToMessageDecoder{protected override void Decode(IChannelHandlerContext context, IByteBuffer input, List<object> output){byte[] array = new byte[input.ReadableBytes];input.GetBytes(input.ReaderIndex, array, 0, input.ReadableBytes);input.Clear();output.Add(array);}}

4.客户端ClientEncoder编码类代码如下

 class ClientEncoder : MessageToByteEncoder<string>{protected override void Encode(IChannelHandlerContext context, string message, IByteBuffer output){byte[] messageBytes = Encoding.UTF8.GetBytes(message);IByteBuffer initialMessage = Unpooled.Buffer(messageBytes.Length);initialMessage.WriteBytes(messageBytes);output.WriteBytes(initialMessage);}}

7. 业务代码

1.业务类(服务端DiscardServerHandler,客户端NettyClientHand)继承ChannelHandlerAdapter类

2.IsSharable 一个handler可以被多个通道共享

3.HandlerAdded和HandlerRemoved 上线和下线事件

4.ChannelActive和ChannelInactive 通道活动和不活动事件

5.ChannelRead 接收事件

 public override void ChannelRead(IChannelHandlerContext context, object message){//if (message is IByteBuffer buffer)//{//    Console.WriteLine($"IByteBuffer方式,从服务端接收:{buffer.ToString(Encoding.UTF8)}");//}if (message is byte[] o){Console.WriteLine($"byte方式,从服务端接收:{Encoding.UTF8.GetString(o)}");}}

6.UserEventTriggered心跳事件,在IdleStateHandler配置读和写是180秒。在180秒没有接收或者发送消息就会触发心跳机制。注意物理拔插网线不会走掉线事件需要用心跳机制处理。

 public override void UserEventTriggered(IChannelHandlerContext context, object evt){if (evt is IdleStateEvent) {IdleStateEvent e = evt as IdleStateEvent;if (e.State == IdleState.AllIdle){//读或者写}else if (e.State == IdleState.ReaderIdle){    //读}else if (e.State == IdleState.WriterIdle) { //写}}}

7.WriteAndFlushAsync发送

服务端发送

channelcontext = dis.channel;
channelcontext?.WriteAndFlushAsync(string.Format("{0}^$end",121345));

客户端发送

clientChannel.WriteAndFlushAsync(string.Format("{0}^$end",message));

8.CloseAsync关闭

服务端关闭

boundChannel.CloseAsync();//释放工作组线程
await Task.WhenAll(bossGroup.ShutdownGracefullyAsync(),workerGroup.ShutdownGracefullyAsync());

客户端关闭


await clientChannel.CloseAsync();
await group.ShutdownGracefullyAsync();

总结

以上就是DotNetty的搭建.

Dotnetty搭建教程相关推荐

  1. win2008怎么配置php,Win2008 PHP 配置环境搭建 教程

    Win2008 PHP 配置环境搭建 教程 一.准备工作 1.所需软件: MySQL数据库:本文用MySQL-essential-5.0.45-win32.msi PHP : 本文用php-5.2.4 ...

  2. es springboot 不设置id_es(elasticsearch)整合SpringCloud(SpringBoot)搭建教程详解

    注意:适用于springboot或者springcloud框架 1.首先下载相关文件 2.然后需要去启动相关的启动文件 3.导入相关jar包(如果有相关的依赖包不需要导入)以及配置配置文件,并且写一个 ...

  3. 宝塔服务器环境好不好_服务器环境怎么搭建?(宝塔环境搭建教程)

    大家好,欢迎来到西安蓝蜻蜓网络讲坛,上期我们讲的是怎样购买服务器,很多小伙伴都知道了购买服务器的方式方法,那么购买服务器后需要怎么搭建服务器环境呢?那么今天,我们就来讲述下服务器环境怎么搭建? 以宝塔 ...

  4. php iis mysql windows2003,Windows Server 2003 IIS6.0+PHP5(FastCGI)+MySQL5环境搭建教程 | 系统运维...

    准备篇 一.环境说明: 操作系统:Windows Server 2003 SP2 32位 PHP版本:php 5.3.14 MySQL版本:MySQL5.5.25 二.相关软件下载: 1.PHP下载地 ...

  5. neo4j中文社区 php,neo4j 社区版搭建教程

    neo4j搭建教程 版本说明 软件 版本 jdk jdk1.8.0_201 neo4j需要提前按照java8 并且配置好jdk neo4j-community 3.5.14 neo4j 社区版 硬件环 ...

  6. nginx+tomcat实现Windows系统下的负载均衡搭建教程

    下面小编就为大家分享一篇nginx+tomcat实现Windows系统下的负载均衡搭建教程,具有很好的参考价值,希望对大家有所帮助 刚入行没多久就听过'负载均衡'的大名,到现在因为工作接触的少,所以没 ...

  7. Nginx独立图片服务器搭建教程

    Nginx独立图片服务器搭建教程 发布时间:2014-06-04编辑:脚本学堂 本文介绍了nginx独立图片服务器的搭建与配置教程,有需要的朋友参考下. 首先,为什么需要独立图片服务器? 现在主流的网 ...

  8. win命令安装 安装cmake_win10下VSCode+CMake+Clang+GCC环境搭建教程图解

    打算用C/C++把基本的数据结构与算法实现一遍, 为考研做准备, 因为只是想实现算法和数据结构, 就不太想用VisualStudio, 感觉VSCode不错, 遂在网上找了一些教程, 结合自己的需求, ...

  9. Quorum企业以太坊环境搭建教程

    Quorum企业以太坊环境搭建教程 Quorum是一个许可制的以太坊联盟区块链实现,包含了金融巨头JP摩根开发的一个GETH分支版本, 可以在节点之间实现私有和快速的交易.Quorum为保证隐私对节点 ...

最新文章

  1. Spark任务提交源码
  2. cassandra本地连接失败_本地网络发现失败的解决方法连接到OS X中的服务器的问题 | MOS86...
  3. 云服务器上安装jboss_jboss的使用和安装
  4. oracle11关闭账户验证,Windows下Oracle11g中使用外部操作系统账户验证
  5. 文件系统缓存dirty_ratio与dirty_background_ratio两个参数区别
  6. 【原】使用Bmob作为iOS后台开发心得——查询关联关系(BmobRelation)
  7. 内网穿透工作笔记001---UDP通信_内网通信原理_P2P点对点通信原理
  8. 给你个选择Mac的理由,浅谈Macos系统的优点
  9. 总结:MySQL备份与恢复的三种方法
  10. 科研论文检索方法入门(计算机领域)
  11. 数学之美:《社交网络》中Facemash算法分析
  12. python学习之路之:import(详细介绍import的各种调用原理和使用方法)
  13. python图形用户界面page_Python+selenium使用PageObject实现UI自动化
  14. Linux 网络命令大全
  15. rasterio实用教程(4)——坐标系转换
  16. np.vstack()函数
  17. 蓝桥杯2017年第八届真题-对局匹配
  18. MAC电脑存储空间占用过高怎么办?
  19. kubernetes pod infra container网络原理
  20. springMVC+poi导出excel

热门文章

  1. 你真的会做项目经理吗
  2. mybatis-plus:根据日期或时间范围查询数据的3种方式
  3. Fusion 360的快捷键大全
  4. PostgreSQL中的距离计算问题 ST_Length
  5. php框架实现原理,Ylmf-PHP框架基本原理
  6. Python获取[2016年统计用区划代码和城乡划分代码(截止2016年07月31日)]
  7. mysql事务的理解学习, 面试不问索引原理就是事务原理
  8. 考研真有那么难吗?过来人分享一下
  9. wowza 配置自己的VOD-Edge 实现一个vod点播
  10. mount不是很熟悉 转载文章了解下 转自http://forum.ubuntu.org.cn/viewtopic.php?f=120t=257333...