建设品牌公司网站,网站制作设及的技术,热搜词排行榜关键词,个人养老金保险KestrelServer是基于Libuv开发的高性能web服务器#xff0c;那我们现在就来看一下它是如何工作的。在上一篇文章中提到了Program的Main方法#xff0c;在这个方法里Build了一个WebHost#xff0c;我们再来看一下代码#xff1a; public static void Main( string [] args) … KestrelServer是基于Libuv开发的高性能web服务器那我们现在就来看一下它是如何工作的。在上一篇文章中提到了Program的Main方法在这个方法里Build了一个WebHost我们再来看一下代码 public static void Main( string [] args) { var host new WebHostBuilder() .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() .UseStartupStartup() .Build(); host.Run(); } 里面有一个UseKestrel方法调用这个方法的作用就是使用KestrelServer作为web server来提供web服务。在WebHost启动的时候调用了IServer的Start方法启动服务由于我们使用KestrelServer作为web server自然这里调用的就是KestrelServer.Start方法那我们来看下KestrelServer的Start方法里主要代码 首先我们发现在Start方法里创建了一个KestrelEngine对象具体代码如下 var engine new KestrelEngine( new ServiceContext { FrameFactory context { return new FrameTContext(application, context); }, AppLifetime _applicationLifetime, Log trace, ThreadPool new LoggingThreadPool(trace), DateHeaderValueManager dateHeaderValueManager, ServerOptions Options }); KestrelEngine构造方法接受一个ServiceContext对象参数ServiceContext里包含一个FrameFactory从名称上很好理解就是Frame得工厂Frame是什么Frame是http请求处理对象每个请求过来后都会交给一个Frame对象进行受理我们这里先记住它的作用后面还会看到它是怎么实例化的。除了这个外还有一个是AppLiftTime它是一个IApplicationLifetime对象它是整个应用生命周期的管理对象前面没有说到这里补充上。 public interface IApplicationLifetime { /// summary /// Triggered when the application host has fully started and is about to wait /// for a graceful shutdown. /// /summary CancellationToken ApplicationStarted { get ; } /// summary /// Triggered when the application host is performing a graceful shutdown. /// Requests may still be in flight. Shutdown will block until this event completes. /// /summary CancellationToken ApplicationStopping { get ; } /// summary /// Triggered when the application host is performing a graceful shutdown. /// All requests should be complete at this point. Shutdown will block /// until this event completes. /// /summary CancellationToken ApplicationStopped { get ; } /// summary /// Requests termination the current application. /// /summary void StopApplication(); } IApplicationLifetime中提供了三个时间点 1ApplicationStarted应用程序已启动 2ApplicationStopping应用程序正在停止 3ApplicationStopped应用程序已停止 我们可以通过CancellationToken.Register方法注册回调方法在上面说到的三个时间点执行我们特定的业务逻辑。IApplicationLifetime是在WebHost的Start方法里创建的如果想在我们自己的应用程序获取这个对象我们可以直接通过依赖注入的方式获取即可。 我们继续回到ServiceContext对象这里面还包含了Log对象用于跟踪日志一般我们是用来看程序执行的过程并可以通过它发现程序执行出现问题的地方。还包含一个ServerOptions它是一个KestrelServerOptions里面包含跟服务相关的配置参数 1ThreadCount服务线程数表示服务启动后要开启多少个服务线程因为每个请求都会使用一个线程来进行处理多线程会提高吞吐量但是并不一定线程数越多越好在系统里默认值是跟CPU内核数相等。 2ShutdownTimeoutThe amount of time after the server begins shutting down before connections will be forcefully closed在应用程序开始停止到强制关闭当前请求连接所等待的时间在这个时间段内应用程序会等待请求处理完如果还没处理完将强制关闭 3LimitsKestrelServerLimits对象里面包含了服务限制参数比如MaxRequestBufferSizeMaxResponseBufferSize 其他参数就不再一个一个说明了。 KestrelEngine对象创建好后通过调用 engine.Start(threadCount)根据配置的threadcount进行服务线程KestrelThread实例化代码如下 public void Start(int count){ for (var index 0; index count; index){Threads.Add(new KestrelThread(this));} foreach (var thread in Threads){thread.StartAsync().Wait();}} 上面的代码会创建指定数量的Thread对象然后开始等待任务处理。KestrelThread是对libuv线程处理的封装。 这些工作都准备好后就开始启动监听服务了这个时候服务就开始接受http请求了我们前面说到了监听socket在listener类中创建ListenerPrimary也是一个Listener下面是listener的start方法 public Task StartAsync( ListenOptions listenOptions, KestrelThread thread) { ListenOptions listenOptions; Thread thread; var tcs new TaskCompletionSource int ( this ); Thread.Post(state { var tcs2 (TaskCompletionSource int ) state; try { var listener ((Listener) tcs2.Task.AsyncState); //创建监听socket listener.ListenSocket listener.CreateListenSocket(); //开始监听,当有连接请求过来后触发ConnectionCallback方法 ListenSocket.Listen(Constants.ListenBacklog, ConnectionCallback, this ); tcs2.SetResult(0); } catch (Exception ex) { tcs2.SetException(ex); } }, tcs); return tcs.Task; } / int / int ConnectionCallback当连接请求过来后被触发在回调方法里进行连接处理分发连接分发代码如下 protected virtual void DispatchConnection(UvStreamHandle socket) { var connection new Connection( this , socket); connection.Start(); } 这个是listener类中的实现我们前面看到只有在线程数为1的情况下才创建Listener对象进行监听否则创建ListenerPrimary监听ListenerPrimay里重写了方法它的实现如下 protected override void DispatchConnection(UvStreamHandle socket) { //这里采用轮询的方式把连接请求依次分发给不同的线程进行处理 var index _dispatchIndex % (_dispatchPipes.Count 1); if (index _dispatchPipes.Count) { // base .DispatchConnection(socket); } else { DetachFromIOCP(socket); var dispatchPipe _dispatchPipes[index]; //这里就是通过命名pipe传递socket给特定的线程 var write new UvWriteReq(Log); write.Init(Thread.Loop); write.Write2( dispatchPipe, _dummyMessage, socket, (write2, status, error, state) { write2.Dispose(); ((UvStreamHandle)state).Dispose(); }, socket); } } 好了连接请求找到处理线程后后面就可以开始处理工作了。ListenerSecondary里的代码比较复杂其实最终都会调用下面的代码完成Connection对象的创建? var connection new Connection( this , socket); connection.Start(); Connection表示的就是当前连接下面是它的构造方法 public Connection(ListenerContext context, UvStreamHandle socket) : base (context) { _socket socket; _connectionAdapters context.ListenOptions.ConnectionAdapters; socket.Connection this ; ConnectionControl this ; ConnectionId GenerateConnectionId(Interlocked.Increment( ref _lastConnectionId)); if (ServerOptions.Limits.MaxRequestBufferSize.HasValue) { _bufferSizeControl new BufferSizeControl(ServerOptions.Limits.MaxRequestBufferSize.Value, this ); } //创建输入输出socket流 Input new SocketInput(Thread.Memory, ThreadPool, _bufferSizeControl); Output new SocketOutput(Thread, _socket, this , ConnectionId, Log, ThreadPool); var tcpHandle _socket as UvTcpHandle; if (tcpHandle ! null ) { RemoteEndPoint tcpHandle.GetPeerIPEndPoint(); LocalEndPoint tcpHandle.GetSockIPEndPoint(); } //创建处理frame这里的framefactory就是前面创建KestrelEngine时创建的工厂 _frame FrameFactory( this ); _lastTimestamp Thread.Loop.Now(); } 然后调用Connection的Start方法开始进行处理这里面直接把处理任务交给Frame处理Start方法实现 public void Start() { Reset(); //启动了异步处理任务开始进行处理 _requestProcessingTask Task.Factory.StartNew( (o) ((Frame)o).RequestProcessingAsync(), //具体的处理方法 this , default (CancellationToken), TaskCreationOptions.DenyChildAttach, TaskScheduler.Default).Unwrap(); _frameStartedTcs.SetResult( null ); } 1 RequestProcessingAsync方法里不再详细介绍了把主要的代码拿出来看一下 。。。。。 //_application就是上一篇文章提到的HostApplication首先调用CreateContext创建HttpContext对象 var context _application.CreateContext( this ); 。。。。。。 //进入处理管道 await _application.ProcessRequestAsync(context).ConfigureAwait( false ); 。。。。。。 ProcessRequestAsync完成处理后把结果输出给客户端好到此介绍完毕。 相关文章 聊聊ASP.NET Core默认提供的这个跨平台的服务器——KestrelServer 原文地址http://www.jianshu.com/p/72b13fc4ae34 .NET社区新闻深度好文微信中搜索dotNET跨平台或扫描二维码关注