原标题:深入理解kestrel的应用

1 前言

之所以写本文章,是因为在我停止维护多年前写的NetworkSocket组件两年多来,还是有一些开发者在关注这个项目,我希望有类似需求的开发者明白为什么要停止更新,可以使用什么更好的方式来替换(其实很大原因是我把时间花在开发WebApiClient上面了)。那时.netcore还没有生下来,asp.net除了蜗居在iis里处理http,其它什么也不能干,而NetworkSocket是这样定义的:

NetworkSocket是一个以中间件(middleware)扩展通讯协议,以插件(plug)扩展服务器功能的支持SSL安全传输的通讯框架;目前支持http、websocket、fast、flex策略与silverlight策略协议。2 Kestrel是什么

谈到asp.netcore,人们自然就想到它的默认服务器kestrel,在很多场景中,人们甚至认为kestrel等于Web服务器,或者说它只能处理http和http之上的东西。本文先在此下个定义:Kestrel是一款基于中间件来处理tcp连接的服务器,并内置了http(包含websocket、SignalR)解析中间件。也就是说,我们完全可以给kestrel添加其它中间件,用来处理非http的连接的业务场景,让kestrel使用一个端口支持多种协议或多协议一个端口一种协议的要求。

2.1 Kestrel的中间件是什么

在asp.netcore的Startup里,我们使用app.UseXXX的扩展方法来应用各种中间件,比如UseRouting、UseStaticFiles等等,它本质上还是调用了 IApplicationBuilder.Use(Func middleware) ,也就说 Func 就是一个中间件。

对应的,在kestrel世界里,也有一个 IConnectionBuilder.Use(Func middleware) , Func 就是kestrel的中间件,我们可以如下安装kestrel的中间件:

kestrel.ListenAnyIP(port: 80, listen =>

{

listen. Use(next => context =>

{

if( true)

{

// 中间件1的逻辑

} else

{

returnnext(context);

}

})

. Use(next => context =>

{

if( true)

{

// 中间件2的逻辑

} else

{

returnnext(context);

}

});

});

值得注意的是,kestrel的最后一个中间处理者是http中间件,以上代码,实际的kestrel已经包含3种处理者(文章后部分有中间件的篇幅,然后就容易理解了),逻辑1、逻辑2和http解析,我们可以简单理解为Startup的app对象,对应kestrel的内置的那个最后中间件。

2.2 Kestrel的ConnectionContext

在kestrel中间件里,最重要的对象就是ConnectionDelegate,它等同于 Func ,我们可以理解为它就是一个Hanlder,传入连接上下文,剩下就是我们要干的工作了,而中间件是除了这个Handler之外,我们还能拿到一个叫next的Handler,我们可以选择是否调用它,如果不调用,流程终止。

ConnectionContext是kestrel的一个Tcp连接抽象,其核心属性是Transport,表示双工传输层的操作对象,另外提供Abort方法用于服务端主动关闭连接。基于ConnectionContext,很容易实现一个自定义协议的tcp双工通讯服务器,相比从Socket写起,我们可能可以减少100倍代码量,而得到的是更高性能的服务。

3 基于Kestrel的SignalR+Redis的推送服务 3.1 协议与ConnectionContext的关系

在我们的这个应用里,一个连接不允许同时使用SignalR和Redis并存协议,也就是说,一个连接在发起第一个请求里,就确定了它整个生命周期里的协议。所以,我们需要分析连接读取到的第一个数据包,确定它是否为Redis协议,如果不是redis协议,我们要将ConnectionContext传达到下一个中间件(即http中间件)。

3.2 使用Redis中间件

如下代码,Use里面就是Redis中间件,里面的个协议分析逻辑:

kestrel.ListenAnyIP(options.Port, listen =>

{

listen.Use(next => asynccontext =>

{

if( awaitProtocol.IsRedisAsync(context))

{

logger.LogDebug( $"{context.RemoteEndPoint} { nameof(ClientType.Redis)} 连接");

awaitredis.HandleAsync(context);

logger.LogDebug( $"{context.RemoteEndPoint} { nameof(ClientType.Redis)} 断开");

}

else

{

logger.LogDebug( $"{context.RemoteEndPoint} { nameof(ClientType.SignalR)} 连接");

awaitnext(context);

logger.LogDebug( $"{context.RemoteEndPoint} { nameof(ClientType.SignalR)} 断开");

}

});

});

Protocol类

///

///连接的协议判断

///

publicstaticclassProtocol

{

///

///返回连接是否为redis协议

///

///

///

publicstaticasyncTask< bool> IsRedisAsync(ConnectionContext connection)

{

varresult = awaitconnection.Transport.Input.ReadAsync;

varstate = IsRedis(result);

connection.Transport.Input.AdvanceTo(result.Buffer.Start);

returnstate;

}

///

///返回数据是否为redis协议

///这里不必严格检查,只要能区分是http还是redis就行

///

///

///

privatestaticboolIsRedis(ReadResult result)

{

if(result.Buffer.IsEmpty)

{

returnfalse;

}

varspan = result.Buffer.FirstSpan;

returnspan.Length > 0 && span[0] == '*';

}

}

3.3 RedisConnectionHandler

在3.2代码里,有一个await redis.HandleAsync(context);这个redis就是RedisConnectionHandler实例,它的功能是处理一个redis连接从建立成功之后到断开的所有逻辑。

既然kestrel基于连接处理中间件,上层的asp.netcore也是基于请求处理中间件,我们完全也可以也依葫芦画瓢,造一个Redis命令中间件Builder,最后将所有Redis中间件串起来,Buid得一个Redis处理委托。

varbuilder = newPipelineBuilder(appServices, context=>

{

// 没有handler来处理

returncontext.Client.ResponseAsync(RedisResponse .Error( "unsupported cmd"));

})

.Use(( context, next) =>

{

this.logger.LogDebug( context.ToString);

// 验证客户端是否已授权

returncontext.Cmd.Name!= RedisCmdName .Auth&& context.Client.IsAuthed== false

? context.Client.ResponseAsync(RedisResponse .Error( "need auth password"))

: next;

});

// 添加各个cmd对应的handler条件分支

appServices

.GetServices

.ForEach(item => builder .When(item .CanHandle, item .HandleAsync));

this.handler= builder .Build;

在RedisConnectionHandler,每收一个Redis命令,将命令包装为RedisContext,然后使用build出来的handler对象来处理这个RedisContext就行。剩下的工作,就是我们一个命令实现一个IRedisCmdHanler对象就行,逻辑完全分开。

IRedisCmdHanler接口:

///

///定义redis命令处理者

///

interfaceIRedisCmdHanler

{

///

///返回是否可以处理

///

///

///

boolCanHandle(RedisContext context);

///

///处理

///

///

///

Task HandleAsync(RedisContext context);

}

3.4 统一Redis和Signal客户端操作接口 ///

///定义客户端的接口

///

publicinterfaceIClient

{

///

///获取唯一标识

///

stringId { get; }

///

///获取连接时间

///

DateTime ConnectedTime { get; }

///

///获取客户端类型

///

[ JsonConverter(typeof(JsonStringEnumConverter))]

ClientType ClientType { get; }

///

///发送消息

///

///

///

Task< bool> SendMessageAsync(Message message);

}

3.5 IClient管理器 3.6 SignalR部分

由于SignalR的内容非常简单,官方文档细节齐全,这里将不作任何讲解了。

4 总结

由于要讲解的内部比较多,篇幅和时间都有限,本文就只从思路上大概讲解Kestrel在多协议连接的场景的使用方式。一句话,中间件的使用,使得这些场景变得简单,那问题来了,什么是中间件,你理解了吗?返回搜狐,查看更多

责任编辑:

kestrel服务器性能,深入理解kestrel的应用相关推荐

  1. views 多个文件夹 netcore_.NET Core中的使用Kestrel服务器理解及应用

    Kestrel是一个基于libuv的跨平台.NET Core web服务器,libuv是一个跨平台的异步I/O库.ASP.NET Core模板项目使用Kestrel作为默认的web服务器. Kestr ...

  2. kestrel web服务器性能对比,Asp.Net Core 3.0 Kestrel服务器下 高性能 WebSocket Server

    最近研究.net core 的各种高性能类型,内存池之类的东西,基于kestrel 服务器的websocket ,写个例子练下手 把原生的Websocket用ArrayPool,Memory改造了下, ...

  3. .NET Core中的使用Kestrel服务器理解

    Kestrel是一个基于libuv的跨平台.NET Core web服务器,libuv是一个跨平台的异步I/O库.ASP.NET Core模板项目使用Kestrel作为默认的web服务器. Kestr ...

  4. ASP.NETCore的Kestrel服务器

    什么是Kestrel服务器 Kestrel是开源的(GitHub提供的源代码),事件驱动的异步I / O服务器,用于在任何平台上托管ASP.NET应用程序.这是一个监听服务器和一个命令行界面.您将侦听 ...

  5. ASP.NET Core的Kestrel服务器

    原文地址----Kestrel server for ASP.NET Core By Tom Dykstra, Chris Ross, and Stephen Halter Kestrel是一个基于l ...

  6. .NET Core 3.0之深入源码理解Kestrel的集成与应用(一)

    写在前面 ASP.NET Core 的 Web 服务器默认采用Kestrel,这是一个基于libuv(一个跨平台的基于Node.js的异步I/O库)的跨平台.轻量级的Web服务器. 在开始之前,先回顾 ...

  7. 服务器性能是什么,什么是服务器性能的显卡,怎么理解?

    什么是服务器性能的显卡,怎么理解? 如果单说""二字就是个伪命题,服务分不同的性能级别,有些刀片器的性能甚至还不如某些发烧级的游戏台式机,那它所用的显卡性能也会比较一般,如果是说哪 ...

  8. 虚机和实体服务器性能,虚机的性能主要与以下几方面有关

    第一.服务器的稳定性与速度. 虚拟主机作为网络服务,最重要的就是系统的稳定性.稳定性左右着虚拟主机的在线率,它直接关系到网站是否能够被访问的问题.虚拟主机的性能的好坏又取决于服务器的配置及.所使用操作 ...

  9. linux 查看服务器性能常用命令

    2019独角兽企业重金招聘Python工程师标准>>> linux 查看服务器性能常用命令 一.top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况, ...

最新文章

  1. c语言装饰,C++设计模式之装饰模式(Decorator)
  2. windows10环境下的RabbitMQ安装步骤(图文)
  3. mysql报错3534_win7下安装MYSQL报错:MYSQL 服务无法启动的3534问题
  4. 这款Web SSH工具超牛逼!
  5. matplotlib.pyplot绘制函数图像希腊字母latex效果设置
  6. 好文转发《我现在是这样编程的》
  7. c语言中的目标程序的正确含义,C语言程序设计练习题整理要点.doc
  8. 1779: 无法言表(map+queue)
  9. Jscript中window.setInterval和window.setTimeout的区别
  10. php邮件代码c语言,C语言实现邮件发送功能(SMTP)源码
  11. es 创建索引_es的基本原理和操作文档
  12. php讲一个正整数前补0,php 数字补零的两种的简单示例
  13. android自定义滤镜,让IjkPlayer支持插入自定义的GPU滤镜方法
  14. Atitit onvif协议获取rtsp地址播放java语言attilx总结
  15. 手机wps怎么设置打印横竖_WPS中横竖打印怎么设置
  16. 服装店如何根据自身情况使用进销存软件?
  17. 性能服务器漫画免费下拉式,奇妙漫画免费漫画
  18. WIN10系统在中国知网下载期刊封面、扉页、目录的PDF版本
  19. JAVA面试题-文思海辉-花旗银行
  20. 什么是测试环境?如何搭建测试环境?

热门文章

  1. 【win11】安装WIN11启用TPM2.0的华硕主板M10H使用英特尔CPU设置PTT解决方案全记录
  2. “不务正业”斗地主?AI青年查道琛想做“被人看到”的研究
  3. Github星标90K?京东架构师一篇讲明白百亿级并发系统架构设计
  4. 电阻应变片式测力传感器弹性体设计要求
  5. RISC-V基金会董事谭章熹:RISC-V,从边缘逐渐向中央扩展
  6. 生信软件 | STAR(测序序列与参考序列比对)
  7. java愤怒的小鸟代码_用java实现小游戏“愤怒的小鸟”附源码和效果演示
  8. CDGA|数据治理让企业数字化转型少走一大截弯路
  9. 世界各国GDP相关面板数据(1960-2019年)
  10. 限流的两种算法以及相关的实现方法