ข้ามไปยังเนื้อหา

Bidirectional Streaming

Bidirectional streaming เปิด stream เดียวที่ ทั้ง client และ server ส่ง message ได้ อิสระและพร้อมกัน ไม่มีฝั่งไหนต้องรออีกฝั่ง message ไหลไปทางไหนก็ได้เมื่อมีอะไรจะพูด

นี่คือรูปแบบสำหรับ session แบบโต้ตอบจริง ๆ: chat, state ของ multiplayer game, การแก้เอกสารร่วมกัน หรือ protocol ไหนก็ตามที่ request กับ response ของตัวเองสลับกันไปมาแทนที่จะเป็นจังหวะ lock-step

sequenceDiagram
  participant C as Client
  participant S as Server
  C->>S: join(room: "general")
  S-->>C: "Sam joined"
  C->>S: "hello everyone"
  S-->>C: "Alex: hi Sam"
  C->>S: "how's the deploy?"
  S-->>C: "Alex: green"
  Note over C,S: แต่ละฝั่งส่งเมื่อไรก็ได้; ลำดับเป็นแบบ per-direction
Bidirectional streaming: message อิสระ สลับกันไปมา

ทั้ง request และ response มี keyword stream:

syntax = "proto3";
package chat.v1;
message ChatMessage {
string from = 1;
string text = 2;
int64 ts = 3;
}
service Chat {
// Both sides stream ChatMessages independently.
rpc Chat(stream ChatMessage) returns (stream ChatMessage);
}

จุดต่างสำคัญจาก stream ทางเดียว: แต่ละฝั่งมักอ่านและเขียน พร้อมกัน การอ่านและเขียนบน stream เดียวจาก goroutine/thread/callback แยกกันนั้นปลอดภัยและเป็นเรื่องปกติ

stream, _ := client.Chat(ctx)
// receive loop (its own goroutine)
go func() {
for {
msg, err := stream.Recv()
if err == io.EOF { return }
if err != nil { log.Println(err); return }
fmt.Printf("%s: %s\n", msg.From, msg.Text)
}
}()
// send loop (main goroutine)
for _, text := range outgoing {
stream.Send(&chatv1.ChatMessage{From: "me", Text: text})
}
stream.CloseSend() // done sending; server may still send

server implementation ก็ทำแบบเดียวกัน: วน Recv แล้วเรียก Send เมื่อมีอะไรจะส่ง — บ่อยครั้งคือกระจาย message ที่รับมาออกไปให้ client อื่นที่ต่ออยู่

  • ลำดับเป็นแบบ per-direction message ที่ client ส่งไปถึง server ตามลำดับ; message ที่ server ส่งไปถึง client ตามลำดับ แต่สองทิศทางเป็นอิสระต่อกัน — ไม่มีลำดับรวมระหว่าง message ของ client กับของ server
  • half-close เป็นแบบข้างเดียว CloseSend (client) หรือการ return (server) จบการส่งของ ฝั่งนั้น ส่วนอีกฝั่ง stream ต่อได้ call จบสมบูรณ์ก็ต่อเมื่อทั้งสองทิศปิด
  • อ่านและเขียนพร้อมกัน อย่า block receive loop ไว้หลัง send loop ไม่งั้น flow-control window เต็มแล้ว deadlock ได้ (บทถัดไป)
  • นี่ไม่ใช่ message broker bidi stream เป็นแบบ point-to-point ระหว่าง client 1 ตัวกับ server 1 ตัว การกระจายไปหา client จำนวนมาก (chat room) เป็น application logic ที่อยู่ข้างบน มักมี pub/sub รองรับ
อะไรนิยาม bidirectional streaming RPC ใน .proto?
bidi stream ให้การรับประกันลำดับแบบไหน?
ทำไมทั้งสองฝั่งมักอ่านและเขียนพร้อมกัน?
จะกระจาย message ของ client หนึ่งไปหา client อื่นจำนวนมาก (chat room) ยังไง?