测试代码运行环境:
OS:Ubuntu 18.04 64bit
.NET Core SDK Version: 3.1.101
源代码版本:release/3.1

Kestrel的本质 - Web Server


Kestrel是http://ASP.NET Core框架内置的默认Web Server 什么是Web Server? 根据维基百科的定义: Web Server是可以处理来自客户端的HTTP协议请求并返回网页的软件或硬件。 因此Kestrel的主要功能就是接收来自网络客户端的HTTP请求,并根据请求返回对应的网页(数据也是一种网页)。

定义 - IServerIHttpApplication<TContext>


http://ASP.NET Core定义了两个基本的接口IServer,及IHttpApplication<TContext>IServer接口定义了Web Server的基本功能,IHttpApplication<TContext>则定义了处理HTTP协议的应用程序的基本功能,我们首先来看下这两个定义:

Web 服务器 - IServer

namespace Microsoft.AspNetCore.Hosting.Server
{/// <summary>/// Represents a server./// </summary>public interface IServer : IDisposable{/// <summary>/// A collection of HTTP features of the server./// </summary>IFeatureCollection Features { get; }/// <summary>/// Start the server with an application./// </summary>/// <param name="application">An instance of <see cref="IHttpApplication{TContext}"/>.</param>/// <typeparam name="TContext">The context associated with the application.</typeparam>/// <param name="cancellationToken">Indicates if the server startup should be aborted.</param>Task StartAsync<TContext>(IHttpApplication<TContext> application, CancellationToken cancellationToken);/// <summary>/// Stop processing requests and shut down the server, gracefully if possible./// </summary>/// <param name="cancellationToken">Indicates if the graceful shutdown should be aborted.</param>Task StopAsync(CancellationToken cancellationToken);}
}

Features 是一个功能集合,其中可以包含所有应用程序需要的,用以处理HTTP协议各个阶段和组成部分的功能集,以接口的形式注入到Features中。

StartAsync方法可以启动IServer对象,用来接受用户请求。包含两个参数:IHttpApplication<TContext>CancellationTokenIHttpApplicatoin<TContext>是最终处理HTTP请求的应用程序入口点,在ASP.NET Core应用程序中,默认的IHttpApplication<TContext>实现是:HostingApplication,我们会在稍后的部分进行详细的介绍。 而CancellationToken用来响应中断应用程序启动的请求。

StopAsync方法用来处理停止服务的请求,接受一个参数CancellationToken,用来响应中断停止应用程序的请求。

Http应用程序 - IHttpApplication<TContext>

namespace Microsoft.AspNetCore.Hosting.Server
{/// <summary>/// Represents an application./// </summary>/// <typeparam name="TContext">The context associated with the application.</typeparam>public interface IHttpApplication<TContext>{/// <summary>/// Create a TContext given a collection of HTTP features./// </summary>/// <param name="contextFeatures">A collection of HTTP features to be used for creating the TContext.</param>/// <returns>The created TContext.</returns>TContext CreateContext(IFeatureCollection contextFeatures);/// <summary>/// Asynchronously processes an TContext./// </summary>/// <param name="context">The TContext that the operation will process.</param>Task ProcessRequestAsync(TContext context);/// <summary>/// Dispose a given TContext./// </summary>/// <param name="context">The TContext to be disposed.</param>/// <param name="exception">The Exception thrown when processing did not complete successfully, otherwise null.</param>void DisposeContext(TContext context, Exception exception);}
}

IHttpApplication<TContext>接口的定义包含了三个方法: CreateContext方法用来创建处理请求的上下文中所需要的所有相关数据,组成Context对象,由接口的实现自己定义类型, ProcessRequestAsync方法使用CreateContext方法创建的Context对象处理本次请求。 DisposeContext方法在完成请求的处理后,负责释放Context对象。

实现 - KestrelServer

http://ASP.NET Core提供了默认的IServerKestrelServer,下面我们就来看看KestrelServer具体都做了些什么。

KestrelServer 定义在dotnet/aspnetcore项目中(GITHUB REPO)。 项目名称为:Microsoft.AspNetCore.Server.Kestrel.Core 名称空间:Microsoft.AspNetCore.Server.Kestrel.Core 源代码

服务器启动:端口监听,协议解析及请求处理。

我们先看一下KestrelServer.StartAsync()方法的代码实现:

public async Task StartAsync<TContext>(IHttpApplication<TContext> application, CancellationToken cancellationToken){try{if (!BitConverter.IsLittleEndian){throw new PlatformNotSupportedException(CoreStrings.BigEndianNotSupported);}ValidateOptions();if (_hasStarted){// The server has already started and/or has not been cleaned up yetthrow new InvalidOperationException(CoreStrings.ServerAlreadyStarted);}_hasStarted = true;ServiceContext.Heartbeat?.Start();async Task OnBind(ListenOptions options){// Add the HTTP middleware as the terminal connection middlewareoptions.UseHttpServer(ServiceContext, application, options.Protocols);var connectionDelegate = options.Build();// Add the connection limit middlewareif (Options.Limits.MaxConcurrentConnections.HasValue){connectionDelegate = new ConnectionLimitMiddleware(connectionDelegate, Options.Limits.MaxConcurrentConnections.Value, Trace).OnConnectionAsync;}var connectionDispatcher = new ConnectionDispatcher(ServiceContext, connectionDelegate);var transport = await _transportFactory.BindAsync(options.EndPoint).ConfigureAwait(false);// Update the endpointoptions.EndPoint = transport.EndPoint;var acceptLoopTask = connectionDispatcher.StartAcceptingConnections(transport);_transports.Add((transport, acceptLoopTask));}await AddressBinder.BindAsync(_serverAddresses, Options, Trace, OnBind).ConfigureAwait(false);}catch (Exception ex){Trace.LogCritical(0, ex, "Unable to start Kestrel.");Dispose();throw;}}

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类处理用户请求。

internal class HttpConnectionMiddleware<TContext>{private readonly ServiceContext _serviceContext;private readonly IHttpApplication<TContext> _application;private readonly HttpProtocols _protocols;public HttpConnectionMiddleware(ServiceContext serviceContext, IHttpApplication<TContext> application, HttpProtocols protocols){_serviceContext = serviceContext;_application = application;_protocols = protocols;}public Task OnConnectionAsync(ConnectionContext connectionContext){var memoryPoolFeature = connectionContext.Features.Get<IMemoryPoolFeature>();var httpConnectionContext = new HttpConnectionContext{ConnectionId = connectionContext.ConnectionId,ConnectionContext = connectionContext,Protocols = _protocols,ServiceContext = _serviceContext,ConnectionFeatures = connectionContext.Features,MemoryPool = memoryPoolFeature.MemoryPool,Transport = connectionContext.Transport,LocalEndPoint = connectionContext.LocalEndPoint as IPEndPoint,RemoteEndPoint = connectionContext.RemoteEndPoint as IPEndPoint};var connection = new HttpConnection(httpConnectionContext);return connection.ProcessRequestsAsync(_application);}}

HTTP版本控制 - HttpConnection

当用户创建HttpConnection类时,在初始化过程中,会根据用户请求声明的HTTP协议版本,分别创建对应版本的Connection类,并使用该类处理用户请求:

public async Task ProcessRequestsAsync<TContext>(IHttpApplication<TContext> httpApplication){try{// Ensure TimeoutControl._lastTimestamp is initialized before anything that could set timeouts runs._timeoutControl.Initialize(_systemClock.UtcNowTicks);IRequestProcessor requestProcessor = null;switch (SelectProtocol()){case HttpProtocols.Http1:// _http1Connection must be initialized before adding the connection to the connection managerrequestProcessor = _http1Connection = new Http1Connection<TContext>(_context);_protocolSelectionState = ProtocolSelectionState.Selected;break;case HttpProtocols.Http2:// _http2Connection must be initialized before yielding control to the transport thread,// to prevent a race condition where _http2Connection.Abort() is called just as// _http2Connection is about to be initialized.requestProcessor = new Http2Connection(_context);_protocolSelectionState = ProtocolSelectionState.Selected;break;case HttpProtocols.None:// An error was already logged in SelectProtocol(), but we should close the connection.break;default:// SelectProtocol() only returns Http1, Http2 or None.throw new NotSupportedException($"{nameof(SelectProtocol)} returned something other than Http1, Http2 or None.");}_requestProcessor = requestProcessor;if (requestProcessor != null){var connectionHeartbeatFeature = _context.ConnectionFeatures.Get<IConnectionHeartbeatFeature>();var connectionLifetimeNotificationFeature = _context.ConnectionFeatures.Get<IConnectionLifetimeNotificationFeature>();// These features should never be null in Kestrel itself, if this middleware is ever refactored to run outside of kestrel,// we'll need to handle these missing.Debug.Assert(connectionHeartbeatFeature != null, nameof(IConnectionHeartbeatFeature) + " is missing!");Debug.Assert(connectionLifetimeNotificationFeature != null, nameof(IConnectionLifetimeNotificationFeature) + " is missing!");// Register the various callbacks once we're going to start processing requests// The heart beat for various timeoutsconnectionHeartbeatFeature?.OnHeartbeat(state => ((HttpConnection)state).Tick(), this);// Register for graceful shutdown of the serverusing var shutdownRegistration = connectionLifetimeNotificationFeature?.ConnectionClosedRequested.Register(state => ((HttpConnection)state).StopProcessingNextRequest(), this);// Register for connection closeusing var closedRegistration = _context.ConnectionContext.ConnectionClosed.Register(state => ((HttpConnection)state).OnConnectionClosed(), this);await requestProcessor.ProcessRequestsAsync(httpApplication);}}catch (Exception ex){Log.LogCritical(0, ex, $"Unexpected exception in {nameof(HttpConnection)}.{nameof(ProcessRequestsAsync)}.");}finally{if (_http1Connection?.IsUpgraded == true){_context.ServiceContext.ConnectionManager.UpgradedConnectionCount.ReleaseOne();}}}

HTTP1和HTTP2处理HTTP协议的方式有所不同,HTTP1协议解析完成后,会立即调用IHttpApplication<TContext>处理请求,HTTP2协议解析完成后,会再次调用ThreadPool.UnsafeQueueUserWorkItem()方法等待线程池可用线程。

结束语

Kestrel服务的代码量并不下,其中主要是辅助接受用户请求和解析HTTP协议的代码,在这里不做详细的介绍,各位读者有兴趣的,可以详细阅读源代码。

我们看到,Kestrel服务在接受和处理请求时,都用到了线程池,可以极大的提高服务器的吞吐量。

后面,我们还会详细介绍系统默认的IHttpApplication<TContext>实现,看看ASP.NET Core是如何将HTTP转发到Controller和Action,其中又有哪些精妙的代码呢。

敬请期待。

server接收dtu透传代码_深入ASP.NET Core源代码之 - Web Server Kestrel相关推荐

  1. server接收dtu透传代码_ESP8266 STM32 HTTP json透传实验

    关于如何建立一个HTTP的虚拟测试桩的方法如下,通过SoapUI建立一个HTTP测试桩,用来模拟远端HTTP服务器. https://blog.csdn.net/russ44/article/deta ...

  2. server接收dtu透传代码_Swoole学习笔记二:初探server与client(Client同步)

    1.搭建server.php代码 <?php //创建Server对象,监听 127.0.0.1:9501端口 $serv = new swoole_server("127.0.0.1 ...

  3. server接收dtu透传代码_Gopher2020大会干货总结:代码技巧篇

    Gopher2020大会已经结束了几天,圈内大牛的分享可谓干货满满,分享内容涉及到诸多的业务.框架.理念等,本文系会后粗略整理,主要是将一些干货内容总结.分类:本文内容不涉及业务.框架以及设计理念,整 ...

  4. 4g dtu透传模块

    4g dtu透传模块,是一款支持双向透明传输的产品,用户使用无需关心复杂的协议,产品为双向透传,只需要简单配置即可.同时产品为4G全网通,支持国内全部运营商网络,通讯模组采用CTA1系列模组,高性价比 ...

  5. asp编程工具_使用ASP.NET Core构建RESTful API的技术指南

    译者荐语:利用周末的时间,本人拜读了长沙.NET技术社区翻译的技术文章<微软RESTFul API指南>,打算按照步骤写一个完整的教程,后来无意中看到了这篇文章,与我要写的主题有不少相似之 ...

  6. 为什么你需要将代码迁移到ASP.NET Core 2.0?

    随着 .NET Core 2.0 的发布,.NET 开源跨平台迎来了新的时代.开发者们可以选择使用命令行.个人喜好的文本编辑器.Visual Studio 2017 15.3 和 Visual Stu ...

  7. asp.net core 2.0 web api + Identity Server 4 + angular 5 可运行前后台源码

    前台使用angular 5, 后台是asp.net core 2.0 web api + identity server 4. 从头编写asp.net core 2.0 web api 基础框架: 第 ...

  8. azure上传代码_深入了解Azure Data Studio:更多代码和更少GUI

    azure上传代码 In the previous two articles, Starting your journey with Azure Data Studio and Developing ...

  9. 移动联通电信DTU 透传DTU 无线远距离传输

    计讯物联透传DTU,移动.联通.电信5G/4G网络,满足偏远地区无线远距离数据传输需求,广泛应用于工业.农业.环保.水利.气象等行业,实现数据采集上报远程控制中心. 4G DTU TD210 1.标准 ...

最新文章

  1. qt在表格中如何画线_如何把EXCEL的表格完整的粘贴到WORD文件中
  2. numpy和pandas的基础索引切片
  3. Intel® Nehalem/Westmere架构/微架构/流水线 (4) - 执行引擎
  4. 简析面向对象中的继承,原型链,闭包之继承
  5. 江门计算机职称考试时间,江门职称计算机考试时间
  6. 最简单的图文教程,几步完成Git的公私钥配置
  7. 互联网快讯:极米Z6X Pro、极米H3S音画表现出众;快狗打车赴港IPO;vivo回应造车传闻
  8. 折叠屏市场起风,华为、OPPO“你追我赶”
  9. Fiddler+雷电模拟器进行APP抓包
  10. 网络安全用什么编程语言_网络安全的5种最佳编程语言
  11. 72个免费学习网站,涵盖所有,你值得拥有!【非推广】
  12. 解决:docker容器内可以访问web应用,端口映射到宿主机却无法访问,错误代码:curl: 56 Recv failure: 连接被对方重设
  13. 20221208 浪客剑心 追忆篇
  14. 初学(一):不积跬步,无以成千里 【基础知识必备】
  15. 7-13 非常弹的球 (30 分)
  16. [转帖]Photoshop把美女照片转成清爽的矢量图
  17. 利用Floyd-Steinberg方法(dithering),将灰度图转换为二值图
  18. 链路追踪eagleEye介绍
  19. 地方政府公共服务注意力指标(100+关键词)2001-2021年
  20. twitter申请开发者帐号失败

热门文章

  1. 新的一年即将到来,分享2023年火爆的行业和值得做的副业兼职项目
  2. OCR技术系列之一 字符识别技术总览
  3. OpenCV函数应用:基于二值图像的三种孔洞填充方法记录(附python,C++代码)
  4. 亚马逊首席技术官:2023年及未来五大技术趋势预测 | 美通社头条
  5. c语言hook微信dll,Hook微信 - 拦截新消息函数,获取消息内容
  6. 宁夏最新建筑八大员(资料员)真题题库及答案解析
  7. linux申请大块内存,linux 内存看一篇就够了(多图)
  8. jav 通过HttpClient实现调用外部接口两种请求方式(get/post)
  9. 计算机word茶的功效,乌龙茶的功效与作用 Microsoft Word 文档
  10. 【笔记】IAR重命名工程文件名称