0Pricing
C# Academy · บทเรียน

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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. พื้นฐาน gRPC และ Protobuf
  2. RPC แบบเอกภาพและการสตรีมจากเซิร์ฟเวอร์
  3. การสตรีมจากไคลเอ็นต์และแบบสองทิศทาง
  4. เส้นตาย การยกเลิก และตัวดักจับ
← กลับไปที่ C# Academy