聊聊ASP.NET Core默认提供的这个跨平台的服务器——KestrelServer

跨平台是ASP.NET Core一个显著的特性,而KestrelServer是目前微软推出了唯一一个能够真正跨平台的Server。KestrelServer利用一个名为KestrelEngine的网络引擎实现对请求的监听、接收和响应。KetrelServer之所以具有跨平台的特质,源于KestrelEngine是在一个名为libuv的跨平台网络库上开发的。


目录

一、libuv

二、KestrelServer

三、KestrelServerOptions

四、ApplicationLifetime

五、设置监听地址


一、libuv

image说起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,前者与应用的生命周期管理有关。


   1: public class KestrelServer : IServer

   2: {   

   3:     public IFeatureCollection Features { get; }

   4:     public KestrelServerOptions Options { get; }

   5:  

   6:     public KestrelServer(IOptions<KestrelServerOptions> options,IApplicationLifetime applicationLifetime, 

              ILoggerFactory loggerFactory);

   7:     public void Dispose();

   8:     public void Start<TContext>(IHttpApplication<TContext> application);

   9: }


我们一般通过调用WebHostBuilder的扩展方法UseKestrel方法来完成对KestrelServer的注册。如下面的代码片段所示,UseKestrel方法具有两个重载,其中一个具有同一个类型为Action<KestrelServerOptions>的参数,我们可以利用这个参数直接完成对KestrelServerOptions的设置。


   1: public static class WebHostBuilderKestrelExtensions

   2: {

   3:     public static IWebHostBuilder UseKestrel(this IWebHostBuilder hostBuilder);

   4:     public static IWebHostBuilder UseKestrel(this IWebHostBuilder hostBuilder, 

              Action<KestrelServerOptions> options);

   5: }


三、KestrelServerOptions

由于Server负责请求的监听、接收和响应,所以Server是影响整个Web应用响应能力和吞吐量最大的因素之一,为了更加有效地使用Server,我们往往针对具体的网络负载状况对其作针对性的设置。对于KestrelServer来说,在构造函数中作为参数指定的KestrelServerOptions对象代表针对它所做的设置。我们针对KestrelServer所做的设置主要体现在KestrelServerOptions类型的如下5个属性上。


   1: public class KestrelServerOptions

   2: {   

   3:     //省略其他成员

   4:     public int MaxPooledHeaders { get; set; }

   5:     public int MaxPooledStreams { get; set; }

   6:     public bool NoDelay { get; set; }

   7:     public TimeSpan ShutdownTimeout { get; set; }

   8:     public int ThreadCount { get; set; }

   9: }


KestrelServerOptions注册的KetrelServer在管道中会以依赖注入的方式被创建,并采用构造器注入的方式提供其构造函数的参数options,由于这个参数类型为IOptions<KestrelServerOptions>,所以我们利用Options模型以配置的方式来指定KestrelServerOptions对象承载的设置。比如我们可以将KestrelServer的相关配置定义在如下一个JSON文件中。


   1: { 

   2:     "noDelay"         : false, 

   3:     "shutdownTimeout" : "00:00:10", 

   4:     "threadCount"     : 10 

   5: } 


为了让应用加载这么一个配置文件(文件名假设为“KestrelServerOptions.json”),我们只需要在启动类型(Startup)类的ConfigureServces方法中按照如下的方式利用ConfigurationBuilder加载这个配置文件并生成相应的Configuration对象,最后按照Options模型的编程方式完成KestrelServerOptions类型和该对象的映射即可。


   1: public class Startup

   2: {

   3:     //其他成员

   4:     public void ConfigureServices(IServiceCollection services)

   5:     {

   6:         IConfiguration configuration = new ConfigurationBuilder()

   7:             .AddJsonFile("KestrelServerOptions.json")

   8:             .Build();

   9:         services.Configure<KestrelServerOptions>(configuration);

  10:     }

  11: }


四、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: }


  • 通过一个Hello World程序来认识一下ASP.NET Core的请求处理管道

  • 创建一个“迷你版”的管道模拟ASP.NET Core管道对HTTP请求的处理流程

  • 通过模拟管道为你演示ASP.NET Core管道是如何处理HTTP请求的

  • ASP.NET Core的HTTP请求处理管道是如何一步步建立起来的?


  • 学习ASP.NET Core,你必须知道“中间件”是什么?中间件如何注册?请求处理管道是如何通过中间件构建的?

  • ASP.NET Core 管道= 服务器+ HttpApplication,HttpApplication是个什么玩意儿?



请扫描此二维码或者搜索“大内老A”关注蒋金楠(Artech)微信公众帐号,你将会得到及时的高质量技术文章推送信息。

内容转载自公众号

大内老A
大内老A
了解更多

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

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

相关文章

pdfbox java.lang.outofmemoryerror_Apache PDFBox 1.8.11 发布,Java 的 PDF 处理类

Apache PDFBox 1.8.11 发布&#xff0c;此版本是个增量 bug 修复版本&#xff0c;包括大量 bug 修复和改进。现已提供下载&#xff1a;主要改进内容&#xff1a;Bug 修复[PDFBOX-962] - All sort of Problems when importing Xfdf files into PDFs ->damaged pdfs and NPEs[…

Java8 Striped64 和 LongAdder

转载自 Java8 Striped64 和 LongAdder 数据 STRIPING 根据维基百科的这段说明&#xff1a;In computer data storage, data striping is the technique of segmenting logically sequential data, such as a file, so that consecutive segments are stored on different phys…

Roslyn项目系统简介

发布15年后&#xff0c;Microsoft终于开始替换Visual Studio中基于COM的C#和Visual Basic项目系统。Microsoft谈及很多有必要放弃目前所用系统的原因&#xff1a; 原生且基于COM单线程并与UI线程绑定难以通过和&#xff08;不同用途的&#xff09;子类型类扩展到聚合之外与Visu…

fastdfs 集群 java_FastDFS集群部署(转载 写的比较好)

之前介绍过关于FastDFS单机部署&#xff0c;详见博文&#xff1a;FastDFSNginx(单点部署)事例下面来玩下FastDFS集群部署&#xff0c;实现高可用(HA)服务器规划&#xff1a;跟踪服务器1【主机】(Tracker Server)&#xff1a;192.100.139.121跟踪服务器2【备机】(Tracker Server…

简析.NET Core 以及与 .NET Framework的关系

至2002微软公司推出.NET平台已近15年&#xff0c;在互联网快速迭代的浪潮中&#xff0c;许多语言已被淘汰&#xff0c;同时也有更多新的语言涌现&#xff0c;但 .Net 依然坚挺的站在系统开发平台的一线阵营中&#xff0c;并且随着.NET Core 即将到来(2016年6月27日)的正式版&am…

Jdk1.8 JUC源码增量解析(2)-atomic-LongAdder和LongAccumulator

转载自 Jdk1.8 JUC源码增量解析(2)-atomic-LongAdder和LongAccumulator功能简介&#xff1a;LongAdder是jdk1.8提供的累加器&#xff0c;基于Striped64实现。它常用于状态采集、统计等场景。AtomicLong也可以用于这种场景&#xff0c;但在线程竞争激烈的情况下&#xff0c;Long…

mysql 密码hash算法_如何用hash创建一个mySQL用户(‘sha256’,$salt.$password)?

我肯定错过了什么.我想为select-only事务设置数据库用户帐户,但mysql不允许我在创建用户帐户时选择密码的哈希方法.这失败了&#xff1a;GRANT SELECT ON myDB.* TO selectuserlocalhostIDENTIFIED BY hash(sha256, salted-myfakelongrandompasswordstring);错误1064(42000)&am…

为什么微软逐步转变为开源公司

微软目前拥有自己的 BSD Unix 操作系统&#xff0c;支持 Ubuntu 作为 Windows 10 的一个子系统&#xff0c;最近又将 Xamarin 软件开发工具包开源&#xff0c;所有这些意味着微软已不再是比尔盖茨和史蒂夫鲍尔默的微软了。 我知道这很难令人相信&#xff0c;但微软确实正大步走…

Jdk1.8 JUC源码增量解析(1)-atomic-Striped64

转载自 Jdk1.8 JUC源码增量解析(1)-atomic-Striped64功能简介&#xff1a;Striped64是jdk1.8提供的用于支持如Long累加器&#xff0c;Double累加器这样机制的基础类。Striped64的设计核心思路就是通过内部的分散计算来避免竞争(比如多线程CAS操作时的竞争)。Striped64内部包含…

java内部类选择题_java内部类详解(附相关面试题)

说起内部类这个词&#xff0c;想必很多人都不陌生&#xff0c;但是又会觉得不熟悉。原因是平时编写代码时可能用到的场景不多&#xff0c;用得最多的是在有事件监听的情况下&#xff0c;并且即使用到也很少去总结内部类的用法。今天我们就来一探究竟。一.内部类基础在Java中&am…

开源,新的平台之战

近日&#xff0c;OpenDaylight项目的执行总监Neela Jacques在文章《开源的转变&#xff1a;一种新的平台战争》 中提到&#xff1a;开源已经成为软件公司业务战略的关键&#xff0c;是一种新的平台之战。 多年来&#xff0c;开源软件似乎处于技术产业的边缘。而如今&#xff0c…

java下载图片到手机相册_Unity保存图片到Android手机且更新相册

Android 保存图片到设备前言:在许多的应用或游戏中,大多都有保存图片或者截图等等的功能,这篇文档我们的目的是通过 Unity 保存图片,并且调用 Andorid 中的更新相册的原生方法.流程步骤:编写更新相册的 Android 原生接口 -> Unity 编写保存图片逻辑以及调用更新相册 Android…

如何在 Java 中正确使用 wait, notify 和 notifyAll – 以生产者消费者模型为例

转载自 如何在 Java 中正确使用 wait, notify 和 notifyAll – 以生产者消费者模型为例 wait, notify 和 notifyAll&#xff0c;这些在多线程中被经常用到的保留关键字&#xff0c;在实际开发的时候很多时候却并没有被大家重视。本文对这些关键字的使用进行了描述。 在 Java 中…

.NET Core 使用Dapper 操作MySQL

.NET Core 使用Dapper 操作MySQL 数据库&#xff0c; .NET Core 使用Dapper。 目前官方没有出.NET Core MySQL 驱动&#xff0c;但是已经有第三方进行改动封装出.NET Core MySQL Connector 预览版。 Dapper 也已经出了 .NET Core 预览版。 Dapper dot net 是一个轻量型的ORM&a…

Angular 2与TypeScript概览

迄今为止&#xff0c;在创建Web应用方面&#xff0c;AngularJS是当前最为流行的JavaScript框架。如今&#xff0c;Angular 2和TypeScript通过一种非常类似于Java 8的语法&#xff0c;使真正面向对象的Web开发成为了主流。 据Google的工程主管Brad Green介绍&#xff0c;有130万…

正确使用 Volatile 变量

转载自 Java 理论与实践 - 正确使用 Volatile 变量 - volatile 变量使用指南Java 语言中的 volatile 变量可以被看作是一种 “程度较轻的 synchronized”&#xff1b;与 synchronized 块相比&#xff0c;volatile 变量所需的编码较少&#xff0c;并且运行时开销也较少&#xf…

java龟兔赛跑设计思路_JAVA程序设计(09)-----面对对象设计初级应用 龟兔赛跑

1.乌龟和兔子共有属性和方法 做成父类 避免重复代码package com.lovo;/*** 类&#xff1a; 动物* author Abe* 属性&#xff1a; 名字 步距 总距离 睡觉的日子*/public class Animal {protected String name;protected int step;protected int distance;protected int sleepDay…

16年国庆假期期间兼职所悟

2016年9月25日&#xff0c;学校放假了&#xff01;&#xff01;&#xff01; 学校放假11天&#xff0c;10月7号才开学&#xff0c;除了晚上上个夜班之外别的时间都在闲着&#xff0c;这么大的自己感觉闲着真不是滋味&#xff0c;于是开始疯狂的在58上找工作&#xff0c;心里想…

python flask项目过程_Python 开发过程遇到的问题

另一方面&#xff0c;也是因为时间原因&#xff0c;没有事先系统了解 python 的具体内容&#xff0c;所以开发过程中基本都是拿 java 的东西往 python 里面套。比如&#xff1a;某个功能用 java 的 ArrayList 可以解决&#xff0c;那 python 中有没有类似的东西呢&#xff1f;j…

Java 中的双重检查(Double-Check)

转载自 Java 中的双重检查&#xff08;Double-Check&#xff09; 在 Effecitve Java 一书的第 48 条中提到了双重检查模式&#xff0c;并指出这种模式在 Java 中通常并不适用。该模式的结构如下所示&#xff1a; public Resource getResource() { if (resource null) { …