.NET 雲原生架構師訓練營(ASP .NET Core 整體概念推演)--學習筆記

MingsonZheng發表於2021-12-30

演化與完善整體概念

  • ASP .NET Core 整體概念推演
  • 整體概念推演到具體的形式

ASP .NET Core 整體概念推演

ASP .NET Core 其實就是通過 web framework 處理 HTTP 請求並提供 HTTP 響應

web framework 由程式設計師使用,它包括 ASP .NET Core,Express,spring 等等組成

這樣我們就完成了對 ASP .NET Core 的底層建模,接下來對 HTTP 請求和 HTTP 響應進行細化

對於原始 HTTP 請求,伺服器通過監聽配置對 IP 埠進行監聽

IP 埠與 Socket 網路建立連線,Socket 網路連線分為 input stream 和 output stream

input stream 接收並轉化 HTTP 請求連線(C# 可識別),包括 HTTPContext

HTTP 請求連線經過處理之後生成 output stream

整體概念推演到具體的形式

Endpoint 有一個 Options 配置,用於配置 Socket

TransportFactory 分為 SocketTransportFactory 和 LiburyTransportFactory

TransportFactory 繫結 ConnectionListener,ConnectionListener 監聽 Socket 請求

基於 Socket 建立 SocketConnection,組成 ConnectionContext

建立之後通過 Start 方法,開始接收傳送請求,對應 Socket 網路連線的 output stream 到處理之前的過程

接下來通過原始碼找到上述的過程:https://github.com/dotnet/aspnetcore/

在 src/Servers/Kestrel/Kestrel 目錄下有一個 WebHostBuilderKestrelExtensions 的擴充套件方法注入了 KestrelServerImpl

services.AddSingleton<IServer, KestrelServerImpl>();

KestrelServerImpl 是繼承自 IServer 的介面,IServer 是在 Hosting 中的,在 IServer 中有一個 StartAsync 的方法

Task StartAsync<TContext>(IHttpApplication<TContext> application, CancellationToken cancellationToken) where TContext : notnull;

在 KestrelServerImpl 的 StartAsync 方法中我們可以找到一個 OnBind 的方法

async Task OnBind(ListenOptions options, CancellationToken onBindCancellationToken)

在這個 OnBind 方法中可以看到整個 options 在 ListenOptions 裡面,而在 ListenOptions 裡面可以看到 EndPoint 屬性

public EndPoint EndPoint { get; internal set; }

監聽實際上會被拆解成好幾個方法,首先是一個繫結的方法,把 EndPoint 傳入到 TransportManager 的繫結方法

options.EndPoint = await _transportManager.BindAsync(options.EndPoint, multiplexedConnectionDelegate, options, onBindCancellationToken).ConfigureAwait(false);

TransportManager 的繫結方法使用了 TransportFactory 的繫結方法

var transport = await _multiplexedTransportFactory.BindAsync(endPoint, features, cancellationToken).ConfigureAwait(false);

TransportFactory 是一個 IConnectionListenerFactory,它有兩個實現:SocketTransportFactory,LiburyTransportFactory

在 SocketTransportFactory 的繫結方法中會產生一個 SocketConnectionListener 的監聽器

var transport = new SocketConnectionListener(endpoint, _options, _logger);

SocketConnectionListener 是由 SocketConnectionListenerFactory 產生的,SocketConnectionListenerFactory 繼承自 IConnectionListenerFactory

建立 SocketConnectionListener 監聽器之後呼叫 StartAcceptLoop 方法傳入 connectionListener

StartAcceptLoop(new GenericConnectionListener(transport), c => connectionDelegate(c), endpointConfig);

在 StartAcceptLoop 方法中開始接收

var acceptLoopTask = connectionDispatcher.StartAcceptingConnections(connectionListener);

在 StartAcceptingConnections 中呼叫了 listener 的 AcceptAsync 方法接收

var connection = await listener.AcceptAsync();

SocketConnectionListener 的 AcceptAsync 方法會產生一個 ConnectionContext

public ValueTask<ConnectionContext?> AcceptAsync(CancellationToken cancellationToken = default)

這個 ConnectionContext 由 SocketConnectionContextFactory 建立

return _factory.Create(acceptSocket);

Create 方法建立了一個 SocketConnection,這個連線裡面有 InputOptions 和 OutputOptions

var connection = new SocketConnection(socket,
    _memoryPool,
    setting.Scheduler,
    _logger,
    setting.SocketSenderPool,
    setting.InputOptions,
    setting.OutputOptions,
    waitForData: _options.WaitForDataBeforeAllocatingBuffer);

建立之後直接啟動,這是一個自啟動的過程

connection.Start();

在 StartAcceptingConnections 得到 SocketConnection 後建立 KestrelConnection,建立之後的轉化由 _connectionDelegate 執行

var kestrelConnection = new KestrelConnection<T>(
    id, _serviceContext, _transportConnectionManager, _connectionDelegate, connection, Log);

在 KestrelConnection 的執行方法 ExecuteAsync 裡面,呼叫了 _connectionDelegate

await _connectionDelegate(connectionContext);

接下來全部交給 HttpConnectionMiddleware 處理,看一下如何在 KestrelServerImpl 中構建建立

options.UseHttpServer(ServiceContext, application, options.Protocols, addAltSvcHeader);
var connectionDelegate = options.Build();

在 UseHttpServer 中建立 HttpConnectionMiddleware

var middleware = new HttpConnectionMiddleware<TContext>(serviceContext, application, protocols, addAltSvcHeader);

在 HttpConnectionMiddleware 中開啟 HttpConnectionContext 的執行

var httpConnectionContext = new HttpConnectionContext(
    connectionContext.ConnectionId,
    protocols,
    altSvcHeader,
    connectionContext,
    _serviceContext,
    connectionContext.Features,
    memoryPoolFeature?.MemoryPool ?? System.Buffers.MemoryPool<byte>.Shared,
    localEndPoint,
    connectionContext.RemoteEndPoint as IPEndPoint);
httpConnectionContext.Transport = connectionContext.Transport;

var connection = new HttpConnection(httpConnectionContext);

return connection.ProcessRequestsAsync(_application);

在 ProcessRequestsAsync 中開始 requestProcessor 的 Context 的轉化協議

public async Task ProcessRequestsAsync<TContext>(IHttpApplication<TContext> httpApplication) where TContext : notnull

作業

在瞭解完 asp .net core 第2層的架構之後, 從 HttpConnectionMiddleware 開始,把 KestrelConnection 到 HttpContext 的轉化過程用OPD 進行細化

課程連結

https://appsqsyiqlk5791.h5.xiaoeknow.com/v1/course/video/v_5f39bdb8e4b01187873136cf?type=2

知識共享許可協議

本作品採用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。

歡迎轉載、使用、重新發布,但務必保留文章署名 鄭子銘 (包含連結: http://www.cnblogs.com/MingsonZheng/ ),不得用於商業目的,基於本文修改後的作品務必以相同的許可釋出。

如有任何疑問,請與我聯絡 (MingsonZheng@outlook.com) 。

相關文章