.NET CORE学习笔记系列(6)——KestrelServer
原文:http://www.cnblogs.com/artech/p/KestrelServer.html
跨平台是ASP.NET Core一个显著的特性,而KestrelServer是目前微软推出了唯一一个能够真正跨平台的Server。KestrelServer利用一个名为KestrelEngine的网络引擎实现对请求的监听、接收和响应。KetrelServer之所以具有跨平台的特质,源于KestrelEngine是在一个名为libuv的跨平台网络库上开发的。
一、libuv
说起libuv,就不得不谈谈libev,后者是Unix系统上一个事件循环和事件模型的网络库。libev因其具有的高性能成为了继lievent和Event perl module之后一套最受欢迎的网络库。由于Libev不支持Windows,有人在libev之上创建了一个抽象层以屏蔽平台之间的差异,这个抽象层就是libuv。libuv在Windows平台上是采用IOCP的形式实现的,右图揭示了libuv针对Unix和Windows的跨平台实现原理。到目前为止,libuv支持的平台已经不限于Unix和Windows了,包括Linux(2.6)、MacOS和Solaris (121以及之后的版本)在内的平台在libuv支持范围之内。
二、KestrelServer
如下所示的代码片段体现了KestrelServer这个类型的定义。除了实现接口IServer定义的Features属性之外,KestrelServer还具有一个类型为KestrelServerOptions的只读属性Options。这个属性表示对KestrelServer所作的相关设置,我们在调用构造函数时通过输入参数options所代表的IOptions<KestrelServerOptions>对象对这个属性进行初始化。构造函数还具有另两个额外的参数,它们的类型分别是IApplicationLifetime和ILoggerFactory,后者用于创建记录日志的Logger,前者与应用的生命周期管理有关。
public class KestrelServer : IServer
{
public IFeatureCollection Features { get; }
public KestrelServerOptions Options { get; }
public KestrelServer(IOptions<KestrelServerOptions> options,IApplicationLifetime applicationLifetime, ILoggerFactory loggerFactory);
public void Dispose();
public void Start<TContext>(IHttpApplication<TContext> application);
}
我们一般通过调用WebHostBuilder的扩展方法UseKestrel方法来完成对KestrelServer的注册。如下面的代码片段所示,UseKestrel方法具有两个重载,其中一个具有同一个类型为Action<KestrelServerOptions>的参数,我们可以利用这个参数直接完成对KestrelServerOptions的设置。
public static class WebHostBuilderKestrelExtensions
{
public static IWebHostBuilder UseKestrel(this IWebHostBuilder hostBuilder);
public static IWebHostBuilder UseKestrel(this IWebHostBuilder hostBuilder, Action<KestrelServerOptions> options);
}
三、KestrelServerOptions
由于Server负责请求的监听、接收和响应,所以Server是影响整个Web应用响应能力和吞吐量最大的因素之一,为了更加有效地使用Server,我们往往针对具体的网络负载状况对其作针对性的设置。对于KestrelServer来说,在构造函数中作为参数指定的KestrelServerOptions对象代表针对它所做的设置。我们针对KestrelServer所做的设置主要体现在KestrelServerOptions类型的如下5个属性上。
public class KestrelServerOptions
{
//省略其他成员
public int MaxPooledHeaders { get; set; }
public int MaxPooledStreams { get; set; }
public bool NoDelay { get; set; }
public TimeSpan ShutdownTimeout { get; set; }
public int ThreadCount { get; set; }
}
KestrelServerOptions注册的KetrelServer在管道中会以依赖注入的方式被创建,并采用构造器注入的方式提供其构造函数的参数options,由于这个参数类型为IOptions<KestrelServerOptions>,所以我们利用Options模型以配置的方式来指定KestrelServerOptions对象承载的设置。比如我们可以将KestrelServer的相关配置定义在如下一个JSON文件中。
{
"noDelay" : false,
"shutdownTimeout" : "00:00:10",
}
为了让应用加载这么一个配置文件(文件名假设为“KestrelServerOptions.json”),我们只需要在启动类型(Startup)类的ConfigureServces方法中按照如下的方式利用ConfigurationBuilder加载这个配置文件并生成相应的Configuration对象,最后按照Options模型的编程方式完成KestrelServerOptions类型和该对象的映射即可。
public class Startup
{
//其他成员
public void ConfigureServices(IServiceCollection services)
{
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("KestrelServerOptions.json")
.Build();
services.Configure<KestrelServerOptions>(configuration);
}
}
四、ApplicationLifetime
我们将所有实现了IApplicationLifetime接口的所有类型及其对应对象统称为ApplicationLifetime。从命名的角度来看,ApplicationLifetime貌似是对当前应用生命周期的描述,而实际上它存在的目的仅仅是在应用启动和关闭(只要是关闭)时对相关组件发送通知而已。如下面的代码片段所示,IApplicationLifetime接口具有三个CancellationToken类型的属性(ApplicationStarted、ApplicationStopping和ApplicationStopped),我们可以利用它们是否已经被取消(Cancel)确定当前应用的状态(已经开启、正在关闭和已经关闭)。如果试图关闭应用,StopApplication方法应该被调用以发出应用正在被关闭的通知。对于KestrelServer来说,如果请求处理线程中发生未被处理异常,它会调用这个方法。
1: public interface IApplicationLifetime
2: {
3: CancellationToken ApplicationStarted { get; }
4: CancellationToken ApplicationStopping { get; }
5: CancellationToken ApplicationStopped { get; }
6:
7: void StopApplication();
8: }
ASP.NET Core默认使用的ApplicationLifetime是具有如下定义的一个同名类型。可以看出它实现的三个属性返回的CancellationToken对象是通过三个对应的CancellationTokenSource生成。除了实现IApplicationLifetime接口的StopApplication方法用于发送“正在关闭”通知之外,这个类型还定义了额外两个方法(NotifyStarted和NotifyStopped)用于发送“已经开启/关闭”的通知。
1: public class ApplicationLifetime : IApplicationLifetime
2: {
3: private readonly CancellationTokenSource _startedSource = new CancellationTokenSource();
4: private readonly CancellationTokenSource _stoppedSource = new CancellationTokenSource();
5: private readonly CancellationTokenSource _stoppingSource = new CancellationTokenSource();
6:
7: public CancellationToken ApplicationStarted
8: {
9: get { return this._startedSource.Token; }
10: }
11: public CancellationToken ApplicationStopped
12: {
13: get { return this._stoppedSource.Token; }
14: }
15: public CancellationToken ApplicationStopping
16: {
17: get { return this._stoppingSource.Token; }
18: }
19:
20: public void NotifyStarted()
21: {
22: this._startedSource.Cancel(false);
23: }
24: public void NotifyStopped()
25: {
26: this._stoppedSource.Cancel(false);
27: }
28: public void StopApplication()
29: {
30: this._stoppingSource.Cancel(false);
31: }
32: }
一个ASP.NET Core应用利用管道处理请求,所以管道的生命周期等同于应用自身的生命周期。当我们调用Run方法开启WebHost时,请求处理管道被构建出来。如果管道在处理请求时发生未被处理的异常,管道的Sever会调用ApplicationLifeTime对象的StopApplication方法向WebHost发送关闭应用的通知以便后者执行一些回收释放工作。
五、设置监听地址
在演示的实例中,我们实际上并不曾为注册的KestrelServer指定一个监听地址,从运行的效果我们不难看出,WebHost在这种情况下会指定“http://localhost:5000”为默认的监听地址,Server的监听地址自然可以显式指定。在介绍如何通过编程的方式为Server指定监听地址之前,我们有先来认识一个名为ServerAddressesFeature的特性。
我们知道表示Server的接口IServer中定义了一个类型为IFeatureCollection 的只读属性Features,它表示用于描述当前Server的特性集合,ServerAddressesFeature作为一个重要的特性,就包含在这个集合之中。我们所说的ServerAddressesFeature对象是对所有实现了IServerAddressesFeature接口的所有类型及其对应对象的统称,该接口具有一个唯一的只读属性返回Server的监听地址列表。ASP.NET Core默认使用的ServerAddressesFeature是具有如下定义的同名类型。
1: public interface IServerAddressesFeature
2: {
3: ICollection<string> Addresses { get; }
4: }
5:
6: public class ServerAddressesFeature : IServerAddressesFeature
7: {
8: public ICollection<string> Addresses { get; }
9: }
对于WebHost在通过依赖注入的方式创建的Server,由它的Features属性表示的特性集合中会默认包含这么一个ServerAddressesFeature对象。如果没有一个合法的监听地址被添加到这个 ServerAddressesFeature对象的地址列表中,WebHost会将显式指定的地址(一个或者多个)添加到该列表中。我们显式指定的监听地址实际上是作为WebHost的配置保存在一个Configuration对象上,配置项对应的Key为“server.urls”,WebHostDefaults的静态只读属性ServerUrlsKey返回的就是这么一个Key。
1: new WebHostBuilder()
2: .UseSetting(WebHostDefaults.ServerUrlsKey, "http://localhost:3721/")
3: .UseMyKestrel()
4: .UseStartup<Startup>()
5: .Build()
6: .Run();
WebHost的配置最初来源于创建它的WebHostBuilder,后者提供了一个UseSettings方法来设置某个配置项的值,所以我们可以采用如下的方式来指定监听地址(“http://localhost:3721/”)。不过,针对监听地址的显式设置,最直接的编程方式还是调用WebHostBuilder的扩展方法UseUrls,如下面的代码片段所示,该方法的实现逻辑与上面完全一致。
1: public static class WebHostBuilderExtensions
2: {
3: public static IWebHostBuilder UseUrls(this IWebHostBuilder hostBuilder, params string[] urls)
4: =>hostBuilder.UseSetting(WebHostDefaults.ServerUrlsKey, string.Join(ServerUrlsSeparator, urls)) ;
5: }
.NET CORE学习笔记系列(6)——KestrelServer的更多相关文章
- .NET CORE学习笔记系列(2)——依赖注入[7]: .NET Core DI框架[服务注册]
原文https://www.cnblogs.com/artech/p/net-core-di-07.html 包含服务注册信息的IServiceCollection对象最终被用来创建作为DI容器的IS ...
- .NET CORE学习笔记系列(2)——依赖注入[6]: .NET Core DI框架[编程体验]
原文https://www.cnblogs.com/artech/p/net-core-di-06.html 毫不夸张地说,整个ASP.NET Core框架是建立在一个依赖注入框架之上的,它在应用启动 ...
- .NET CORE学习笔记系列(2)——依赖注入[5]: 创建一个简易版的DI框架[下篇]
为了让读者朋友们能够对.NET Core DI框架的实现原理具有一个深刻而认识,我们采用与之类似的设计构架了一个名为Cat的DI框架.在上篇中我们介绍了Cat的基本编程模式,接下来我们就来聊聊Cat的 ...
- .NET CORE学习笔记系列(2)——依赖注入[4]: 创建一个简易版的DI框架[上篇]
原文https://www.cnblogs.com/artech/p/net-core-di-04.html 本系列文章旨在剖析.NET Core的依赖注入框架的实现原理,到目前为止我们通过三篇文章从 ...
- .NET CORE学习笔记系列(2)——依赖注入【3】依赖注入模式
原文:https://www.cnblogs.com/artech/p/net-core-di-03.html IoC主要体现了这样一种设计思想:通过将一组通用流程的控制权从应用转移到框架中以实现对流 ...
- .NET CORE学习笔记系列(2)——依赖注入【2】基于IoC的设计模式
原文:https://www.cnblogs.com/artech/p/net-core-di-02.html 正如我们在<控制反转>提到过的,很多人将IoC理解为一种“面向对象的设计模式 ...
- .NET CORE学习笔记系列(2)——依赖注入【1】控制反转IOC
原文:https://www.cnblogs.com/artech/p/net-core-di-01.html 一.流程控制的反转 IoC的全名Inverse of Control,翻译成中文就是“控 ...
- .NET CORE学习笔记系列 开篇介绍
ASP.NET Core学习和使用了一段时间了,好记性不如烂笔头,通过查阅官网学习文档和一些大神们的博客总结一下.主要路线先总结一下ASP.NET Core的基础知识,然后是ASP.NET Core ...
- .NET CORE学习笔记系列(5)——ASP.NET CORE的运行原理解析
一.概述 在ASP.NET Core之前,ASP.NET Framework应用程序由IIS加载.Web应用程序的入口点由InetMgr.exe创建并调用托管,初始化过程中触发HttpApplicat ...
随机推荐
- java基础(十四)-----详解匿名内部类——Java高级开发必须懂的
在这篇博客中你可以了解到匿名内部类的使用.匿名内部类要注意的事项.匿名内部类使用的形参为何要为final. 使用匿名内部类内部类 匿名内部类由于没有名字,所以它的创建方式有点儿奇怪.创建格式如下: n ...
- 一条项目中常用的linux命令引发的经典算法题
小时候家里定了<读者>的月刊,里面记录一个故事:说有有个偏僻的乡村一日突然来了一个美女,她携着万贯家财子女在当地安家落户,成了当地的乡绅.她让她的子女世世代代的保守这个秘密,直到这个秘密不 ...
- 带着新人学springboot的应用08(springboot+jpa的整合)
这一节的内容比较简单,是springboot和jpa的简单整合,jpa默认使用hibernate,所以本质就是springboot和hibernate的整合. 说实话,听别人都说spring data ...
- SQL语句查询表结构
SQL语句查询表结构 刚刚在做一个小项目,数据库中一张表有20来个字段,用我以前做的一个.NET实体类生成器一个一个的输入还是闲麻烦,于是打算找个时间来重新的改造一个那个.NET实体类,能够通过选 ...
- RabbitMQ消息队列(七)-通过fanout模式将消息推送到多个Queue中(.Net Core版)
前面第六章我们使用的是direct直连模式来进行消息投递和分发.本章将介绍如何使用fanout模式将消息推送到多个队列. 有时我们会遇到这样的情况,多个功能模块都希望得到完整的消息数据.例如一个log ...
- git版本控制工具的使用
目录 git版本管理工具使用 一丶Git的下载与安装 1.windows下的git的下载与安装 2.linux下的git安装 二丶常用命令 三丶Git仓库 1.配置仓库信息 2.仓库的创建于管理 四丶 ...
- Kubernetes审计日志方案
前言 当前Kubernetes(K8S)已经成为事实上的容器编排标准,大家关注的重点也不再是最新发布的功能.稳定性提升等,正如Kubernetes项目创始人和维护者谈到,Kubernetes已经不再是 ...
- SpringCloud系列——Ribbon 负载均衡
前言 Ribbon是一个客户端负载均衡器,它提供了对HTTP和TCP客户端的行为的大量控制.我们在上篇(猛戳:SpringCloud系列——Feign 服务调用)已经实现了多个服务之间的Feign调用 ...
- DSAPI多功能组件编程应用-文件类
[DSAPI.DLL下载地址] 本节内容,是属于"无需过多说明"就能使用的功能.由于实在是太简单,我就简单地示例一下. DSAPI.文件类.获取可读性强的字节大小信息(&q ...
- DSAPI多功能组件编程应用-反射相关
[DSAPI.DLL下载地址] 在.Net中,反射技术是一种入门困难,熟用快速的东西,对于没有接触过反射技术的程序员来说的确是头疼的,看一旦自己写过了,上手就非常简单了.在本节,将部分.N ...