zoukankan      html  css  js  c++  java
  • 聊聊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: }
  • 相关阅读:
    windows中dos命令指南
    HDU 2084 数塔 (dp)
    HDU 1176 免费馅饼 (dp)
    HDU 1004 Let the Balloon Rise (map)
    变态杀人狂 (数学)
    HDU 2717 Catch That Cow (深搜)
    HDU 1234 开门人和关门人 (模拟)
    HDU 1070 Milk (模拟)
    HDU 1175 连连看 (深搜+剪枝)
    HDU 1159 Common Subsequence (dp)
  • 原文地址:https://www.cnblogs.com/artech/p/KestrelServer.html
Copyright © 2011-2022 走看看