양방향 흐름 전송과 ASP.NET Core 3.0의 gRPC 소개
: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
4
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 작성자 감사합니다.저희의 나눔을 원하신다면 좋아요, 즐겨찾기 눌러주세요.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.