RPC แบบเอกภาพและการสตรีมจากเซิร์ฟเวอร์
ใช้งานการเรียกแบบเอกภาพและการสตรีมจากฝั่งเซิร์ฟเวอร์ เพื่อส่งข้อมูลจากเซิร์ฟเวอร์ไปยังไคลเอ็นต์แบบเรียลไทม์
RPC แบบเอกภาพและการสตรีมจากเซิร์ฟเวอร์ เป็นบทเรียน C# Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C# Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C# Academy มีบทเรียนทั้งหมด 4 บทเรียน
ชนิด RPC ของ gRPC
gRPC รองรับรูปแบบ RPC สี่แบบ ได้แก่ แบบเอกภาค (คำขอหนึ่งรายการและการตอบกลับหนึ่งรายการ) การสตรีมจากเซิร์ฟเวอร์ (ไคลเอ็นต์ส่งหนึ่งรายการ และเซิร์ฟเวอร์ส่งหลายรายการ) การสตรีมจากไคลเอ็นต์ และ การสตรีมสองทิศทาง บทเรียนนี้ครอบคลุมสองรูปแบบแรก
RPC แบบเอกภาค: รูปแบบพื้นฐาน
แบบเอกภาคเป็นรูปแบบที่ง่ายที่สุด คือหนึ่งคำขอและหนึ่งการตอบกลับ ลักษณะคล้ายการเรียกฟังก์ชันทั่วไป แต่ส่งผ่าน HTTP/2 โดยใช้การเข้ารหัส Protobuf
// .proto definition
service OrderService {
rpc GetOrder (GetOrderRequest) returns (OrderResponse);
}
message GetOrderRequest { int32 id = 1; }
message OrderResponse { int32 id = 1; string status = 2; double total = 3; }การสร้าง RPC แบบเอกภาค
เขียนทับเมธอดพื้นฐานที่สร้างขึ้น ServerCallContext จะให้ข้อมูลเมทาดาทา โทเค็นการยกเลิก กำหนดเวลา และข้อมูลเพียร์
public class OrderService : OrderService.OrderServiceBase
{
private readonly IOrderRepository _repo;
public OrderService(IOrderRepository repo) => _repo = repo;
public override async Task<OrderResponse> GetOrder(
GetOrderRequest request,
ServerCallContext context)
{
var order = await _repo.GetByIdAsync(request.Id, context.CancellationToken);
if (order is null)
throw new RpcException(new Status(StatusCode.NotFound, "Order not found"));
return new OrderResponse
{
Id = order.Id,
Status = order.Status.ToString(),
Total = (double)order.Total
};
}
}การเรียก RPC แบบคำขอเดียวจากไคลเอ็นต์
ไคลเอ็นต์ที่สร้างขึ้นมีทั้งเมธอดที่ดูเหมือนทำงานแบบพร้อมกันและเมธอด async ที่ทำงานแบบอะซิงโครนัสจริง ควรใช้รูปแบบ Async ในการใช้งานจริงเสมอ
var client = new OrderService.OrderServiceClient(channel);
// Async call with cancellation
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
var reply = await client.GetOrderAsync(
new GetOrderRequest { Id = 42 },
cancellationToken: cts.Token);
Console.WriteLine($"Order {reply.Id}: {reply.Status} - ${reply.Total}");การสตรีมจากเซิร์ฟเวอร์: การกำหนดโพรโต
การสตรีมจากเซิร์ฟเวอร์จะเพิ่มคีย์เวิร์ด stream ไว้หน้าชนิดข้อมูลการตอบกลับ เซิร์ฟเวอร์จะส่งหลายข้อความผ่านการเชื่อมต่อเดียวกันก่อนปิดสตรีม
service StockService {
// Client sends one symbol, server streams price updates
rpc WatchStock (WatchRequest) returns (stream StockUpdate);
}
message WatchRequest { string symbol = 1; }
message StockUpdate { string symbol = 1; double price = 2; int64 timestamp = 3; }การนำการสตรีมจากเซิร์ฟเวอร์ไปใช้
ใช้ IServerStreamWriter<T> เพื่อส่งข้อความ เมธอดจะคืนค่าเป็น Task — ให้เขียนข้อมูลจนเสร็จ แล้วจึงคืนค่า
public override async Task WatchStock(
WatchRequest request,
IServerStreamWriter<StockUpdate> responseStream,
ServerCallContext context)
{
while (!context.CancellationToken.IsCancellationRequested)
{
var price = await _market.GetPriceAsync(request.Symbol);
await responseStream.WriteAsync(new StockUpdate
{
Symbol = request.Symbol,
Price = price,
Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
});
await Task.Delay(1000, context.CancellationToken);
}
}การรับสตรีมจากเซิร์ฟเวอร์ที่ไคลเอ็นต์
ใช้ await foreach กับ ResponseStream.ReadAllAsync() เพื่อประมวลผลแต่ละข้อความทันทีที่มาถึง
using var call = client.WatchStock(
new WatchRequest { Symbol = "MSFT" });
await foreach (var update in call.ResponseStream.ReadAllAsync())
{
Console.WriteLine($"{update.Symbol}: ${update.Price:F2}");
}
// Continues until server closes the stream or client cancelsการยกเลิกสตรีมจากเซิร์ฟเวอร์
ส่ง CancellationToken เมื่อเริ่มการเรียกเพื่อหยุดสตรีมจากฝั่งไคลเอ็นต์ เซิร์ฟเวอร์จะได้รับการยกเลิกผ่านโทเค็นของตัวเอง
var cts = new CancellationTokenSource();
// Cancel after 30 seconds
cts.CancelAfter(TimeSpan.FromSeconds(30));
using var call = client.WatchStock(
new WatchRequest { Symbol = "AAPL" },
cancellationToken: cts.Token);
try
{
await foreach (var update in
call.ResponseStream.ReadAllAsync(cts.Token))
{
Console.WriteLine($"Price: {update.Price}");
}
}
catch (OperationCanceledException)
{
Console.WriteLine("Stream cancelled.");
}ข้อมูลเมตา: ส่วนหัวคำขอและข้อมูลต่อท้าย
gRPC รองรับข้อมูลเมตา (คู่คีย์-ค่า) ที่ส่งเป็นส่วนหัวก่อนการตอบกลับ และเป็นข้อมูลต่อท้ายหลังการตอบกลับ ใช้ข้อมูลเหล่านี้สำหรับโทเค็นยืนยันตัวตน รหัสติดตาม หรือเคอร์เซอร์แบ่งหน้า
// Server: send initial metadata
await context.WriteResponseHeadersAsync(new Metadata
{
{ "x-correlation-id", Guid.NewGuid().ToString() }
});
// Server: set trailing metadata
context.ResponseTrailers.Add("x-total-count", "1500");
// Client: read headers
var headers = await call.ResponseHeadersAsync;
var trailerId = headers.GetValue("x-correlation-id");gRPC-Web สำหรับไคลเอ็นต์บนเบราว์เซอร์
เบราว์เซอร์ไม่สามารถใช้ gRPC แบบดิบได้ (ไม่รองรับข้อมูลต่อท้ายของ HTTP/2) ให้ใช้ Grpc.AspNetCore.Web ร่วมกับไคลเอ็นต์ JavaScript grpc-web หรือ Grpc.Net.Client.Web ของ Blazor
// dotnet add package Grpc.AspNetCore.Web
app.UseGrpcWeb();
app.MapGrpcService<GreeterService>().EnableGrpcWeb();
// Blazor client:
var handler = new GrpcWebHandler(GrpcWebMode.GrpcWeb,
new HttpClientHandler());
using var channel = GrpcChannel.ForAddress(
"https://localhost:7042",
new GrpcChannelOptions { HttpHandler = handler });กรณีใช้งานจริง: บริการสตรีมบันทึกเหตุการณ์
บริการรวบรวมบันทึกเหตุการณ์จะสตรีมรายการบันทึกเหตุการณ์ของแอปพลิเคชันไปยังไคลเอ็นต์ตรวจสอบที่เชื่อมต่ออยู่แบบเรียลไทม์ โดยใช้การสตรีมจากเซิร์ฟเวอร์
public override async Task StreamLogs(
LogStreamRequest request,
IServerStreamWriter<LogEntry> responseStream,
ServerCallContext context)
{
await foreach (var log in _logChannel.Reader.ReadAllAsync(
context.CancellationToken))
{
if (log.Level >= request.MinLevel)
{
await responseStream.WriteAsync(new LogEntry
{
Level = log.Level.ToString(),
Message = log.Message,
Timestamp = Timestamp.FromDateTime(log.Timestamp)
});
}
}
}ตรวจสอบความเข้าใจ
คีย์เวิร์ดใดในไฟล์ .proto ที่ระบุว่าเป็น RPC แบบสตรีมจากเซิร์ฟเวอร์
สรุป: RPC แบบคำขอเดียวและการสตรีมจากเซิร์ฟเวอร์
ประเด็นสำคัญ:
- RPC แบบคำขอเดียว: หนึ่งคำขอ หนึ่งการตอบกลับ — รูปแบบที่ใช้บ่อยที่สุด
- การสตรีมจากเซิร์ฟเวอร์: หนึ่งคำขอ และมีข้อความตอบกลับหลายข้อความตามเวลา
- นำการสตรีมจากเซิร์ฟเวอร์ไปใช้โดยเขียนข้อมูลลงใน
IServerStreamWriter<T> - รับสตรีมจากเซิร์ฟเวอร์ด้วย
await foreachบนReadAllAsync() - ใช้ CancellationToken เพื่อหยุดสตรีมอย่างเรียบร้อยจากฝั่งใดก็ได้
- gRPC-Web ช่วยให้ไคลเอ็นต์บนเบราว์เซอร์เรียกใช้บริการ gRPC ได้
คำถามที่พบบ่อย
บทเรียน “RPC แบบเอกภาพและการสตรีมจากเซิร์ฟเวอร์” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “RPC แบบเอกภาพและการสตรีมจากเซิร์ฟเวอร์” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C# Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C# Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “RPC แบบเอกภาพและการสตรีมจากเซิร์ฟเวอร์”
ใช้งานการเรียกแบบเอกภาพและการสตรีมจากฝั่งเซิร์ฟเวอร์ เพื่อส่งข้อมูลจากเซิร์ฟเวอร์ไปยังไคลเอ็นต์แบบเรียลไทม์ คุณปฏิบัติ C# Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C# Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน C# Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “RPC แบบเอกภาพและการสตรีมจากเซิร์ฟเวอร์” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน C# Academy นี้ได้ไหม
ได้ บทเรียน C# Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- พื้นฐาน gRPC และ Protobuf
- RPC แบบเอกภาพและการสตรีมจากเซิร์ฟเวอร์
- การสตรีมจากไคลเอ็นต์และแบบสองทิศทาง
- เส้นตาย การยกเลิก และตัวดักจับ