양방향 흐름 전송과 ASP.NET Core 3.0의 gRPC 소개

10463 단어
원문 관련
     :Eduard Los
     :https://medium.com/@eddyf1xxxer/bi-directional-streaming-and-introduction-to-grpc-on-asp-net-core-3-0-part-2-d9127a58dcdb
 Demo  :https://github.com/f1xxxer/CustomerGrpc

이제 코드를 봅시다.Visual Studio UI 또는 명령줄 명령을 사용하여 gRPC 서비스 항목을 쉽게 만들 수 있습니다:dotnet new grpc-n Your Grpc Service
내 솔루션에서 gRPC 서버와 클라이언트의 코드는 모두 C#에 있습니다.gRPC 서버는 고객의 연결을 관리하고 메시지를 처리하며 모든 연결된 클라이언트에게 메시지를 방송합니다.클라이언트는 고객의 입력을 받아 서버에 보내고 서버의 다른 클라이언트로부터 메시지를 받는다.
CustomerGrpc 프로젝트의 서버 코드를 먼저 살펴보았지만, 그 전에 표준 Startup.cs 및 Program.cs 파일에서 일부 내용을 지적합니다.
public class Startup {
    // This method gets called by the runtime. Use this method to add services to the container.
    // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
    public void ConfigureServices (IServiceCollection services) {
        services.AddGrpc (opts => {
            opts.EnableDetailedErrors = true;
            opts.MaxReceiveMessageSize = 4096;
            opts.MaxSendMessageSize = 4096;
        });
        services.AddTransient ();
        services.AddSingleton ();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure (IApplicationBuilder app, IWebHostEnvironment env) {
        if (env.IsDevelopment ()) {
            app.UseDeveloperExceptionPage ();
        }

        app.UseRouting ();

        app.UseEndpoints (endpoints => {
            endpoints.MapGrpcService ();

            endpoints.MapGet ("/",
                async context => {
                    await context.Response.WriteAsync (
                        "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
                });
        });
    }
}


서비스AdddGrpc();방법은 gRPC를 사용합니다.이 방법은 gRPC 호출을 처리하는 파이프를 구축하는 데 사용되는 다양한 서비스와 중간부품을 추가합니다.Undercover 방법은 GrpcMarker 서비스 클래스를 사용하여 필요한 gRPC 서비스가 모두 추가되었는지 확인하고 기본 HTTP/2 메시지를 조작하는 중간부품도 추가했습니다.GrpcServiceOptions 유형을 통해 서비스의 구성을 제공할 수 있습니다. 이 유형은 나중에 파이프에서 사용할 것입니다.예를 들어, 최대 수신 메시지 크기는 다음과 같이 구성할 수 있습니다.

services.AddGrpc(opts =>
{
    opts.EnableDetailedErrors = true;
    opts.MaxReceiveMessageSize = 4096;
    opts.MaxSendMessageSize = 4096;
});


우리에게 또 다른 흥미로운 방법은 단점 루트에서:endpoints.MapGrpcService();이 방법은 gRPC 서비스를 루트 파이프에 추가합니다.ASP에서.NET Core에서 라우팅 파이프는 중간부품과 기능 간에 공유되므로 MVC 컨트롤러 같은 다른 요청 처리 프로그램을 가질 수 있습니다.기타 요청 처리 프로그램은 구성된 gRPC 서비스와 병행 작업을 합니다.다음 글 참조:

app.UseEndpoints(endpoints =>
{
	endpoints.MapGrpcService();

	endpoints.MapGet("/",	async context =>
		{
			await context.Response.WriteAsync(
				"Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: 						https://go.microsoft.com/fwlink/?linkid=2086909");
		});
});


이제 Kestrel 서버를 구성해야 합니다.
Kestrel gRPC 끝점:
4
  • HTTP/2가 필요합니다

  • 4
  • HTTPS를 사용하여 보호해야 합니다

  • HTTP/2 gRPC에는 HTTP/2 및 ASP 가 필요합니다.NET Core의 gRPC 인증 HttpRequest.Protocol. HTTP/2입니다.
    Kestrel은 대부분의 현대 운영 체제에서 Http/2.를 지원합니다.기본적으로 Kestrel 끝점은 HTTP/1.1 및 HTTP/2 연결을 지원하도록 구성됩니다.
    HTTPS가 gRPC에 사용되는 Kestrel 끝점은 HTTPS 보호를 사용해야 합니다.개발 중,https://localhost:5001ASP가 있는 경우NET Core에서 인증서를 개발하면 HTTPS 종료점이 자동으로 생성됩니다.구성할 필요가 없습니다.프로덕션에서는 HTTPS를 명시적으로 구성해야 합니다.Dell의 경우 다음과 같은 사항이 있습니다.
    
    public class Program
    {
    	public static void Main(string[] args)
    	{
    		CreateHostBuilder(args).Build().Run();
    	}
    
    	// Additional configuration is required to successfully run gRPC on macOS.
    	// For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682
    	public static IHostBuilder CreateHostBuilder(string[] args) =>
    		Host.CreateDefaultBuilder(args)
    			.ConfigureWebHostDefaults(webBuilder =>
    			{
    				webBuilder.ConfigureKestrel(options =>
    				{
    					// Setup a HTTP/2 endpoint without TLS for OSX.
    					options.ListenLocalhost(5001, o => o.Protocols = HttpProtocols.Http2);
    				});
    				webBuilder.UseStartup();
    			});
    }
    
    

    macOS가 전송 계층 보안(Http/2.)을 지원하지 않는다는 알려진 문제점이 있습니다.를 참고하십시오.NET Core gRPC .macOS에서 gRPC 서비스를 성공적으로 실행하려면 다른 설정이 필요합니다.이것이 바로 우리의 상황입니다. 이것이 바로 우리가 옵션에 있어야 하는 이유입니다.ListenLocalhost(5001, o => o.Protocols = HttpProtocols.Http2);TLS 없이 HTTP/2행을 사용하여 TLS를 비활성화하는 이유는 애플리케이션 개발 중에만 사용할 수 있습니다.운영 애플리케이션은 항상 전송 보안을 사용해야 합니다.자세한 내용은 ASP를 참조하십시오.NET Core의 gRPC에서를 참고하십시오.
    이제 GRPC 고객 서비스를 살펴보겠습니다.처음에 우리가 본 것은 우리의 Customer Service 클래스는 Customer Grpc.CustomerService.CustomerServiceBase 클래스가 상속합니다.
    이런 것들은 우리의 것에 기초를 두고 있다.프로토 파일 생성. 파일에서 F12 키를 누르면 자동으로 생성된 코드가 보입니다. 이 코드들은 저희 서비스, 메시지, 통신을 설명합니다.우리 반에서, 우리는 부류를 다시 쓰는 데 두 가지 사용자 정의 방법을 정의했다. 바로 Join Customer Chat과 Send Message ToChat Room. 이것은 기본적으로 모든 우리의 코드가 어떻게 된 일인지이다.JoinCustomerChat은 비교적 간단한 요청/응답 모드를 보여 주었습니다. 우리는 그 중에서 JoinCustomerRequest 고객 정보를 보내고 고객이 JoinCustomerReply에 가입한 채팅방 RoomId에서 수신합니다.
    
    public override async Task JoinCustomerChat (JoinCustomerRequest request, ServerCallContext context) 
    {
        return new JoinCustomerReply { RoomId = await _chatRoomService.AddCustomerToChatRoomAsync (request.Customer) };
    }
    
    

    그리고 더 재미있는 Send Message ToChat Room 방법이 있습니다. 이것은 양방향 흐름의 시범입니다.
    
    public override async Task SendMessageToChatRoom (IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context)
     {
        var httpContext = context.GetHttpContext ();
        _logger.LogInformation ($"Connection id: {httpContext.Connection.Id}");
    
        if (!await requestStream.MoveNext ()) {
            return;
        }
    
        _chatRoomService.ConnectCustomerToChatRoom (requestStream.Current.RoomId, Guid.Parse (requestStream.Current.CustomerId), responseStream);
        var user = requestStream.Current.CustomerName;
        _logger.LogInformation ($"{user} connected");
    
        try {
            while (await requestStream.MoveNext ())
            {
                if (!string.IsNullOrEmpty (requestStream.Current.Message)) 
                {
                    if (string.Equals (requestStream.Current.Message, "qw!", StringComparison.OrdinalIgnoreCase)) {
                        break;
                    }
                    await _chatRoomService.BroadcastMessageAsync (requestStream.Current);
                }
            }
        } 
        catch (IOException)
        {
            _chatRoomService.DisconnectCustomer (requestStream.Current.RoomId, Guid.Parse (requestStream.Current.CustomerId));
            _logger.LogInformation ($"Connection for {user} was aborted.");
        }
    }
    
    

    이 방법의 매개 변수를 자세히 봅시다.IasyncStreamReader request Stream은 클라이언트로부터 온 메시지 흐름을 표시합니다. 우리는 Request Stream을 읽고 교체할 수 있습니다.MoveNext().만약 사용 가능한 메시지가 있다면true로 되돌아오기;다른 메시지 (즉, 흐름이 닫혔음) 가 없으면false를 되돌려줍니다.
    IServerStreamWriter responseStream도 메시지 흐름입니다. 이번에는 클라이언트에게 메시지를 보내는 데 사용할 수 있습니다.
    ServerCallContext context는 호출된 HttpContext, HostName 등의 편리한 속성을 제공합니다.이 방법의 논리는 결코 복잡하지 않다.서버에서 호출을 받았을 때, 먼저 IServerStreamWriter responseStream을 저장하여 클라이언트에게 메시지를 방송하는 데 사용합니다.
    
    _chatRoomService.ConnectCustomerToChatRoom(requestStream.Current.RoomId, Guid.Parse(requestStream.Current.CustomerId), responseStream);
    
    

    그리고while (await request Stream. MoveNext () 순환에서 클라이언트로부터 받은 메시지를 훑어보고 현재 연결된 다른 클라이언트로 방송합니다.
    
    await _chatRoomService.BroadcastMessageAsync(requestStream.Current);
    
    

    BroadcastMessageAsync () 메서드의 코드는 연결된 모든 클라이언트의 응답 흐름을 옮겨다니며 메시지를 기록합니다.
    
    foreach (var customer in chatRoom.CustomersInRoom)
    {
       await customer.Stream.WriteAsync(message);
       Console.WriteLine($"Sent message from {message.CustomerName} to   {customer.Name}");
    }
    
    

    연결 실패를 처리하고 채팅방에서 해당하는 흐름을 삭제하려면try/catch 블록이 하나 더 있습니다.
    
    catch (IOException)
    {
       _chatRoomService.DisconnectCustomer(requestStream.Current.RoomId,     Guid.Parse(requestStream.Current.CustomerId));
       _logger.LogInformation($"Connection for {user} was aborted.");
    }
    
    

    이것은 기본적으로 gRPC와 직접 관련된 모든 서버 논리이다.서비스와 패키지에 추가 기능을 만들었습니다. 여기에서 찾을 수 있습니다.
    이제 우리는 클라이언트 코드를 간단하게 볼 수 있다.먼저 GrpcChannel을 만든 다음 GRPC 클라이언트에 제공합니다.
    
    var channel = GrpcChannel.ForAddress("http://localhost:5001", new GrpcChannelOptions { Credentials = ChannelCredentials.Insecure });
    var client = new CustomerService.CustomerServiceClient(channel);
    
    

    그리고 클라이언트는 JoinCustomerChatAsync를 채팅방의 RoomId로 되돌려줍니다.이후에, 우리는 SendMessageToChatRoom 호출과 메시지 교환을 실행함으로써, 양방향 흐름을 열거나 시작합니다.
    
    using (var streaming = client.SendMessageToChatRoom (new Metadata { new Metadata.Entry ("CustomerName", customer.Name) })) 
    {
        var response = Task.Run (async () => 
        {
            while (await streaming.ResponseStream.MoveNext ()) 
            {
                Console.ForegroundColor = Enum.Parse (streaming.ResponseStream.Current.Color);
                Console.WriteLine ($"{streaming.ResponseStream.Current.CustomerName}: {streaming.ResponseStream.Current.Message}");
                Console.ForegroundColor = Enum.Parse (customer.ColorInConsole);
            }
        });
    
        ...
        
        while (!string.Equals (line, "qw!", StringComparison.OrdinalIgnoreCase)) {
            await streaming.RequestStream.WriteAsync (new ChatMessage {
                Color = customer.ColorInConsole,
                    CustomerId = customer.Id,
                    CustomerName = customer.Name,
                    Message = line,
                    RoomId = joinCustomerReply.RoomId
            });
            line = Console.ReadLine ();
            DeletePrevConsoleLine ();
        }
        await streaming.RequestStream.CompleteAsync ();
    }
    
    

    연결을 열면 백엔드 작업에서 순환을 시작합니다. 이 순환은 응답 흐름에서 메시지를 읽고 컨트롤에 표시합니다.두 번째 순환은 키보드에서 입력을 받아서 서버에 보내는 것입니다.전체적으로 말하자면 코드는 그리 복잡하지 않지만 어디에서 사용하거나 디자인 선택을 해야 하는지를 지적했다.netcore 및 c# 가 자체 gRPC 서비스를 구현하는 곳.
    Eduard Los 작성자 감사합니다.저희의 나눔을 원하신다면 좋아요, 즐겨찾기 눌러주세요.

    좋은 웹페이지 즐겨찾기