演化與完善整體概念
- 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) 。