文章出處

跨平臺是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: }

文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()