测试代码运行环境:
OS:Ubuntu 18.04 64bit
.NET Core SDK Version: 3.1.101
源代码版本:release/3.1
Kestrel的本质 - Web Server
Kestrel是ASP.NET Core框架内置的默认Web Server
什么是Web Server?
根据维基百科的定义:
Web Server是可以处理来自客户端的HTTP协议请求并返回网页的软件或硬件。
因此Kestrel的主要功能就是接收来自网络客户端的HTTP请求,并根据请求返回对应的网页(数据也是一种网页)。
定义 - IServer
、IHttpApplication<TContext>
ASP.NET Core定义了两个基本的接口IServer
,及IHttpApplication<TContext>
,IServer
接口定义了Web Server的基本功能,IHttpApplication<TContext>
则定义了处理HTTP协议的应用程序的基本功能,我们首先来看下这两个定义:
Web 服务器 - IServer
1 | namespace Microsoft.AspNetCore.Hosting.Server |
Features
是一个功能集合,其中可以包含所有应用程序需要的,用以处理HTTP协议各个阶段和组成部分的功能集,以接口的形式注入到Features
中。
StartAsync
方法可以启动IServer对象,用来接受用户请求。包含两个参数:IHttpApplication<TContext>
和CancellationToken
。IHttpApplicatoin<TContext>
是最终处理HTTP请求的应用程序入口点,在ASP.NET Core应用程序中,默认的IHttpApplication<TContext>
实现是:HostingApplication
,我们会在稍后的部分进行详细的介绍。
而CancellationToken
用来响应中断应用程序启动的请求。
StopAsync
方法用来处理停止服务的请求,接受一个参数CancellationToken
,用来响应中断停止应用程序的请求。
Http应用程序 - IHttpApplication<TContext>
1 | namespace Microsoft.AspNetCore.Hosting.Server |
IHttpApplication<TContext>
接口的定义包含了三个方法:CreateContext
方法用来创建处理请求的上下文中所需要的所有相关数据,组成Context
对象,由接口的实现自己定义类型,ProcessRequestAsync
方法使用CreateContext
方法创建的Context
对象处理本次请求。DisposeContext
方法在完成请求的处理后,负责释放Context
对象。
实现 - KestrelServer
ASP.NET Core提供了默认的IServer
:KestrelServer
,下面我们就来看看KestrelServer
具体都做了些什么。
KestrelServer
定义在dotnet/aspnetcore项目中(GITHUB REPO)。
项目名称为:Microsoft.AspNetCore.Server.Kestrel.Core
名称空间:Microsoft.AspNetCore.Server.Kestrel.Core
源代码
服务器启动:端口监听,协议解析及请求处理。
我们先看一下KestrelServer
.StartAsync()
方法的代码实现:
1 | public async Task StartAsync<TContext>(IHttpApplication<TContext> application, CancellationToken cancellationToken) |
Kestrel
首先会检查服务器的字节序,目前是不支持大端序的。
然后检查最大请求长度限制的设置项,以及服务器是否已经启动。
最后,通过AddressBinder
对预先配置的IP地址或终结点(EndPoint)名称进行监听,开始接受客户端的请求。
当每有一个新的HTTP请求通过TCP协议或其他协议和服务器成功简历连接后,AddressBinder使用ThreadPool.UnsafeQueueUserWorkItem()
方法将OnBind()
方法添加到线程池中,等待线程池的调度。
如果此时进程有可用的线程,就会调用OnBind()
方法,处理用户的HTTP请求。
OnBind()
方法默认使用HttpConnectionMiddleware<ServiceContext>
中间件,处理新接入的用户请求,当设置了MaxConcurrentConnections
值为True
时,则会默认使用ConnectionLimitMiddleware
中间件,限制最大可用连接数,如果当前请求数已经达到最大可接受连接数,则拒绝用户的请求并断开连接,否则调用HttpConnectionMiddleware<ServiceContext>
中间件,继续处理用户的请求。
处理HTTP请求 - HttpConnectionMiddleware<ServiceContext>
、HttpConnection
HttpConnectionMiddleware<ServiceContext>
中间件负责组装连接相关的上下文数据HttpConnectionContext
,并使用HttpConnection
类处理用户请求。
1 | internal class HttpConnectionMiddleware<TContext> |
HTTP版本控制 - HttpConnection
当用户创建HttpConnection
类时,在初始化过程中,会根据用户请求声明的HTTP协议版本,分别创建对应版本的Connection类,并使用该类处理用户请求:
1 | public async Task ProcessRequestsAsync<TContext>(IHttpApplication<TContext> httpApplication) |
HTTP1和HTTP2处理HTTP协议的方式有所不同,HTTP1协议解析完成后,会立即调用IHttpApplication<TContext>
处理请求,HTTP2协议解析完成后,会再次调用ThreadPool.UnsafeQueueUserWorkItem()
方法等待线程池可用线程。
结束语
Kestrel
服务的代码量并不下,其中主要是辅助接受用户请求和解析HTTP协议的代码,在这里不做详细的介绍,各位读者有兴趣的,可以详细阅读源代码。
我们看到,Kestrel
服务在接受和处理请求时,都用到了线程池,可以极大的提高服务器的吞吐量。
后面,我们还会详细介绍系统默认的IHttpApplication<TContext>
实现,看看ASP.NET Core是如何将HTTP转发到Controller和Action,其中又有哪些精妙的代码呢。
敬请期待。