에서 사용자 지정 서버를 만듭니다.그물심

10209 단어 dotnet
에서 서버의 내부 작업을 확인합니다.Net 커널을 통해 맞춤형 서버를 구축할 수 있습니다.
사용자 정의 서버를 만들려면 사용자 정의 서버 클래스가 IServer 인터페이스와 그에 상응하는 방법을 실현해야 합니다.구축할 서버는 포트(127.0.0.1:8091)의 localhost에 연결되어 HTTP 요청을 탐지한 다음 HTTP 요청을 응용 프로그램 요청 파이프의 나머지 부분으로 전송합니다.요청을 처리한 후 상응하는 응답을 보냅니다.
먼저 CustomServerExample이라는 콘솔 응용 프로그램 프로젝트를 만듭니다.
프로그램cs는 응용 프로그램의 주요 입구점입니다. 이렇게 해야 합니다.
  class Program
    {
        static void Main(string[] args)
        {
            BuildWebHost(args).Run();
        }

        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseCustomServer(o => o.ListeningEndpoint = @"127.0.0.1:8091")
                .UseStartup<Startup>()
                .Build();
    }
UseCustom Server 메서드는 사용자 정의 서버가 구현하는 엔트리 포인트입니다.또한 서버를 통해 HTTP 트래픽의 엔드포인트를 수신합니다.
UseCustomer Server 메서드를 정의하는 확장 클래스를 만듭니다.
        public static class ServerExtensions
        {
            public static IWebHostBuilder UseCustomServer(this IWebHostBuilder hostBuilder, Action<CustomServerOptions> options)
            {
                return hostBuilder.ConfigureServices(services =>
                {
                    services.Configure(options);
                    services.AddSingleton<IServer, CustomServer>();
                });
            }
        }
위의 확장에서, 우리는 IServer 형식의 단례를 등록하여Custom Server 클래스를 등록하여 응용 프로그램 풀에 주입할 수 있도록 합니다.
이 모든 작업이 완료되면 이제 Custom Server를 구축할 수 있습니다.
IServer 인터페이스에는 다음과 같은 설명이 있습니다.
    //
    // Summary:
    //     Represents a server.
    public interface IServer : IDisposable
    {
        //
        // Summary:
        //     A collection of HTTP features of the server.
        IFeatureCollection Features { get; }

        //
        // Summary:
        //     Start the server with an application.
        //
        // Parameters:
        //   application:
        //     An instance of Microsoft.AspNetCore.Hosting.Server.IHttpApplication`1.
        //
        //   cancellationToken:
        //     Indicates if the server startup should be aborted.
        //
        // Type parameters:
        //   TContext:
        //     The context associated with the application.
        Task StartAsync<TContext>(IHttpApplication<TContext> application, CancellationToken cancellationToken);
        //
        // Summary:
        //     Stop processing requests and shut down the server, gracefully if possible.
        //
        // Parameters:
        //   cancellationToken:
        //     Indicates if the graceful shutdown should be aborted.
        Task StopAsync(CancellationToken cancellationToken);
    }
Features 속성에는 이 서버에 필요한 HTTP 기능과 StartAsync 및 StopAsync 메서드가 포함되어 있습니다.전자는 서버가 필요한 응용 프로그램의 상하문을 시작할 때 호출되고, 후자는 서버가 정상적으로 닫힐 때 호출된다.
Custom Server 클래스는 앞에서 설명한 ServerExtension에서 IServer 유형으로 등록되어 있기 때문에 클래스에서 인터페이스의 모든 서명을 실현합니다.Custom Server는 다음과 같습니다.
    public class CustomServer : IServer
    {
        public CustomServer(IOptions<CustomServerOptions> options)
        {
            Features.Set<IHttpRequestFeature>(new HttpRequestFeature());
            Features.Set<IHttpResponseFeature>(new HttpResponseFeature());

            var serverAddressesFeature = new ServerAddressesFeature();
            serverAddressesFeature.Addresses.Add(options.Value.ListeningEndpoint);
            Features.Set<IServerAddressesFeature>(serverAddressesFeature);
        }

        public IFeatureCollection Features { get; } = new FeatureCollection();

        public void Dispose() { }

        public Task StartAsync<TContext>(IHttpApplication<TContext> application, CancellationToken cancellationToken)
        {
            return Task.Run(() =>
            {
                var listener = new CustomHTTPListener<TContext>(application, Features);
                listener.Listen();
            });
        }
...
    }
구조 함수에서, 우리는 요청과 응답 설정 기능을 가지고 있으며, ServerAddresses Feature의 새로운 실례를 시작하여, 주입된 IOOptions에 탐지 단점을 추가한 다음, 이 기능을 IFeature Collection에 추가합니다.
Custom Server에는 HTTP 요청과 응답을 처리할 수 있는 서버 스누핑 주소가 있습니다.이제 StartAsync로 이동합니다.
서버가 시작되면 CustomHTTPlistener의 새 인스턴스가 만들어지고 HTTP 요청이 수신됩니다.CustomHTTPlistener의 컨텐트
    public class CustomHTTPListener<TContext>
    {
        private IHttpApplication<TContext> application;
        private IFeatureCollection features;
        private string uri;
        private HttpListener listener;

        public CustomHTTPListener(IHttpApplication<TContext> application, IFeatureCollection features)
        {
            this.application = application;
            this.features = features;
            uri = features.Get<IServerAddressesFeature>().Addresses.FirstOrDefault();
            listener = new HttpListener();
            listener.Prefixes.Add(uri);

        }

        public void Listen()
        {
            while (true)
            {
              if (listener.IsListening) return;
                ThreadPool.QueueUserWorkItem(async (_) =>
                {
                    listener.Start();
                    HttpListenerContext ctx = listener.GetContext();
                    var context = (HostingApplication.Context)(object)application.CreateContext(features);
                    context.HttpContext = new CustomHttpContext(features, ctx);
                    await application.ProcessRequestAsync((TContext)(object)context);
                    context.HttpContext.Response.OnCompleted(null, null);
                    //listener.Stop();
                });
            }
        }
    }
탐지기 구조 함수는 IHTTP 응용 프로그램 을 받아들인다. 이것은 응용 프로그램 자체의 실례로 중요한 정보가 응용 프로그램에서 전달되는 파이프라인이다.IFeatureCollection도 매개변수로 사용합니다.HttpListerner의 인스턴스를 초기화하고 응용 프로그램 기능에서 가져온 ui를 탐지기에 추가합니다.접두사방법을 추가합니다.
Listen 방법에서while 순환에서 탐지기가 탐지 중이면 교체를 종료합니다.우리는 탐청 관리를 돕기 위해 스레드 탱크에 의뢰를 추가했다.그리고 탐지기를 시작하여 탐지기의 상하문을 가져오고 그 기능과 응용 프로그램 기능을 CustomHttpContext에 전달합니다. CustomHttpContext는 HttpRequest와 HttpResponse의 파생을 현재 응용 프로그램 상하문에 주입하기 위한 것입니다.
다음은 out CustomHttpContext의 모양입니다.
 public class CustomHttpContext : HttpContext
    {
        private IFeatureCollection features;
        private HttpListenerContext ctx;
        private readonly HttpRequest request;
        private readonly HttpResponse response;

        public CustomHttpContext(IFeatureCollection features, HttpListenerContext ctx)
        {
            this.Features = features;
            Request = new CustomHttpRequest(this, ctx);
            Response = new CustomHttpResponse(this, ctx);
        }

        public override IFeatureCollection Features { get; }

        public override HttpRequest Request { get;  }

        public override HttpResponse Response { get; }

.....
CustomHttpContext는 추상 클래스 HttpContext를 상속합니다. 기본 방법을 실행하고 있습니다.
구조 함수에서 CustomHttpRequest와 CustomHttpResponse를 사용하여 각각 요청과 응답 속성에 계승과 재쓰기를 할당합니다.
CustomHttpRequest를 보십시오. 방법과 경로 속성을 설정했습니다. 이 두 속성은 모두 프로그램 파이프라인에서 경로를 정확하게 요청하는 데 필요한 것입니다.
 public class CustomHttpRequest : HttpRequest
    {
        private CustomHttpContext customHttpContext;
        public CustomHttpRequest(CustomHttpContext customHttpContext, HttpListenerContext ctx)
        {
            this.customHttpContext = customHttpContext;
            Method = ctx.Request.HttpMethod;
            Path = ctx.Request.RawUrl;
        }

        public override string Method { get; set; }
        public override string Scheme { get; set; }
        public override bool IsHttps { get; set; }
        public override HostString Host { get; set; }

....
다음 CustomHttpResponse에서는 완료되지 않은 메서드를 트리거하고 응답 바디를 읽고 HttpListener 응답 흐름에 추가합니다.
...
        public override Stream Body { get; set; } = new MemoryStream();

        public override void OnCompleted(Func<object, Task> callback, object state)
        {
            if (!Body.CanRead) return;
            using (var reader = new StreamReader(Body))
            {
                HttpListenerResponse response = ctx.Response;
                Body.Position = 0;
                var text = reader.ReadToEnd();
                byte[] buffer = System.Text.Encoding.UTF8.GetBytes(text);
                response.ContentLength64 = Body.Length;
                response.ContentLength64 = buffer.Length;
                System.IO.Stream output = response.OutputStream;
                output.Write(buffer, 0, buffer.Length);
                output.Close();
                Body.Flush();
                Body.Dispose();
            }
        }
...
이 모든 일이 끝난 후에도 우리는 여전히 관건적인 노선 처리 부분이 부족하다.그래서 우리는 초창기 회사를 창립할 것이다.프로그램 파이프에 리셋을 추가합니다. 이것은 루트를 처리하는 데 도움을 줄 것입니다.
        public void Configure(IApplicationBuilder app)
        {

            app.MapWhen(c => c.Request.Path == "/foo/bar", config =>
            {
                config.Run(async (context) =>
                {
                    context.Response.StatusCode = 200;
                    await context.Response.WriteAsync("This is Foo Bar!");
                });
            })
            .Run(async (context) =>
            {
                context.Response.StatusCode = 404;
                await context.Response.WriteAsync("Not Found");
            });
        }
이것만 있으면 우리 서버는 운행할 수 있다.우리의 코드를 실행하려면 터미널에서 이런 것이 나오는 것을 보아야 한다.

자신의 서버를 기본 서버로 설정할 필요는 없습니다.netcore 기능이 강하고 웹api는 루트, HTTP 요청, 응답 처리 등 기능을 추상화하고 유도합니다.이 글은 엔진 뚜껑 아래에서 발생하는 일을 이해하는 데 도움을 주는 데 목적을 두고 있다.
온전한 코드 라이브러리는 이곳에서 찾을 수 있다https://github.com/omoabobade/CustomServer

좋은 웹페이지 즐겨찾기