1. บทนำ
ในโค้ดแล็บนี้ คุณจะได้ใช้ gRPC-Python เพื่อสร้างไคลเอ็นต์และเซิร์ฟเวอร์ซึ่งเป็นรากฐานของแอปพลิเคชันการแมปเส้นทางที่เขียนด้วย Python
เมื่อจบบทแนะนำนี้ คุณจะมีไคลเอ็นต์ที่เชื่อมต่อกับเซิร์ฟเวอร์ระยะไกลโดยใช้ gRPC เพื่อรับข้อมูลเกี่ยวกับฟีเจอร์ในเส้นทางของไคลเอ็นต์ สร้างข้อมูลสรุปของเส้นทางของไคลเอ็นต์ และแลกเปลี่ยนข้อมูลเส้นทาง เช่น ข้อมูลอัปเดตการจราจร กับเซิร์ฟเวอร์และไคลเอ็นต์อื่นๆ
บริการนี้กำหนดไว้ในไฟล์ Protocol Buffers ซึ่งจะใช้เพื่อสร้างโค้ดมาตรฐานสำหรับไคลเอ็นต์และเซิร์ฟเวอร์เพื่อให้สื่อสารกันได้ ซึ่งจะช่วยประหยัดเวลาและแรงในการติดตั้งใช้งานฟังก์ชันดังกล่าว
โค้ดที่สร้างขึ้นนี้ไม่เพียงแต่จัดการความซับซ้อนของการสื่อสารระหว่างเซิร์ฟเวอร์และไคลเอ็นต์เท่านั้น แต่ยังจัดการการซีเรียลไลซ์และการดีซีเรียลไลซ์ข้อมูลด้วย
สิ่งที่คุณจะได้เรียนรู้
- วิธีใช้ Protocol Buffers เพื่อกำหนด API ของบริการ
- วิธีสร้างไคลเอ็นต์และเซิร์ฟเวอร์ที่ใช้ gRPC จากคำจำกัดความของ Protocol Buffers โดยใช้การสร้างโค้ดอัตโนมัติ
- ความเข้าใจเกี่ยวกับการสื่อสารแบบสตรีมมิงไคลเอ็นต์-เซิร์ฟเวอร์ด้วย gRPC
Codelab นี้มีไว้สำหรับนักพัฒนา Python ที่เพิ่งเริ่มใช้ gRPC หรือต้องการทบทวน gRPC หรือผู้ที่สนใจสร้างระบบแบบกระจาย ไม่จำเป็นต้องมีประสบการณ์เกี่ยวกับ gRPC มาก่อน
2. ก่อนเริ่มต้น
สิ่งที่คุณต้องมี
- Python 3.9 ขึ้นไป เราขอแนะนำให้ใช้ Python 3.13 ดูวิธีการติดตั้งเฉพาะแพลตฟอร์มได้ที่การตั้งค่าและการใช้งาน Python หรือจะติดตั้ง Python ที่ไม่ใช่ระบบโดยใช้เครื่องมืออย่าง uv หรือ pyenv ก็ได้
- pip เพื่อติดตั้งแพ็กเกจ Python
- venv เพื่อสร้างสภาพแวดล้อมเสมือนของ Python
แพ็กเกจ ensurepip
และ venv
เป็นส่วนหนึ่งของไลบรารีมาตรฐานของ Python และมักจะพร้อมใช้งานโดยค่าเริ่มต้น
อย่างไรก็ตาม การกระจายที่อิงตาม Debian บางรายการ (รวมถึง Ubuntu) เลือกที่จะยกเว้นเมื่อแจกจ่าย Python อีกครั้ง หากต้องการติดตั้งแพ็กเกจ ให้เรียกใช้คำสั่งต่อไปนี้
sudo apt install python3-pip python3-venv
รับโค้ด
Codelab นี้มีโครงร่างซอร์สโค้ดที่สร้างไว้ล่วงหน้าเพื่อช่วยให้คุณเริ่มต้นใช้งานได้ง่ายขึ้น ขั้นตอนต่อไปนี้จะแนะนําวิธีสมัครให้เสร็จสมบูรณ์ รวมถึงการสร้างโค้ด gRPC โดยใช้ปลั๊กอินคอมไพเลอร์ grpc_tools.protoc
Protocol Buffer
grpc-codelabs
ซอร์สโค้ดโครงร่างสำหรับ Codelab นี้อยู่ในไดเรกทอรี codelabs/grpc-python-streaming/start_here หากไม่ต้องการติดตั้งใช้งานโค้ดด้วยตนเอง คุณจะดูซอร์สโค้ดที่เสร็จสมบูรณ์ได้ในไดเรกทอรี completed
ก่อนอื่น ให้สร้างไดเรกทอรีการทำงานของ Codelab แล้วใช้คำสั่ง cd เพื่อเข้าไปในไดเรกทอรีดังกล่าว
mkdir grpc-python-streaming && cd grpc-python-streaming
ดาวน์โหลดและแตกไฟล์ Codelab โดยทำดังนี้
curl -sL https://github.com/grpc-ecosystem/grpc-codelabs/archive/refs/heads/v1.tar.gz \
| tar xvz --strip-components=4 \
grpc-codelabs-1/codelabs/grpc-python-streaming/start_here
หรือคุณจะดาวน์โหลดไฟล์ .zip ที่มีเฉพาะไดเรกทอรี Codelab แล้วแตกไฟล์ด้วยตนเองก็ได้
3. กำหนดข้อความและบริการ
ขั้นตอนแรกคือการกำหนดบริการ gRPC ของแอปพลิเคชัน เมธอด RPC รวมถึงประเภทข้อความคำขอและการตอบกลับโดยใช้ Protocol Buffers บริการของคุณจะให้ข้อมูลต่อไปนี้
- เมธอด RPC ที่เรียกว่า
ListFeatures
,RecordRoute
และRouteChat
ซึ่งเซิร์ฟเวอร์ใช้และไคลเอ็นต์เรียก - ประเภทข้อความ
Point
,Feature
,Rectangle
,RouteNote
และRouteSummary
ซึ่งเป็นโครงสร้างข้อมูลที่แลกเปลี่ยนระหว่างไคลเอ็นต์และเซิร์ฟเวอร์เมื่อเรียกใช้เมธอด RPC
วิธีการ RPC และประเภทข้อความเหล่านี้จะกำหนดไว้ในไฟล์ protos/route_guide.proto
ของซอร์สโค้ดที่ให้ไว้
Protocol Buffers เรียกกันโดยทั่วไปว่า protobuf ดูข้อมูลเพิ่มเติมเกี่ยวกับคำศัพท์ gRPC ได้ที่แนวคิดหลัก สถาปัตยกรรม และวงจรของ gRPC
กำหนดประเภทข้อความ
ในprotos/route_guide.proto
ไฟล์ของซอร์สโค้ด ให้กำหนดPoint
ประเภทข้อความก่อน Point
แสดงคู่พิกัดละติจูด-ลองจิจูดบนแผนที่ สำหรับ Codelab นี้ ให้ใช้จำนวนเต็มสำหรับพิกัด
message Point {
int32 latitude = 1;
int32 longitude = 2;
}
หมายเลข 1
และ 2
เป็นหมายเลขรหัสที่ไม่ซ้ำกันสำหรับแต่ละฟิลด์ในโครงสร้าง message
จากนั้นกำหนดFeature
ประเภทข้อความ Feature
ใช้ฟิลด์ string
สำหรับชื่อหรือที่อยู่ไปรษณีย์ของสิ่งหนึ่งๆ ในสถานที่ที่ระบุโดย Point
ดังนี้
message Feature {
// The name or address of the feature.
string name = 1;
// The point where the feature is located.
Point location = 2;
}
หากต้องการสตรีมจุดหลายจุดภายในพื้นที่ไปยังไคลเอ็นต์ คุณจะต้องมีRectangle
ข้อความที่แสดงสี่เหลี่ยมผืนผ้าละติจูด-ลองจิจูด ซึ่งแสดงเป็น 2 จุดที่อยู่ตรงข้ามกันในแนวทแยง lo
และ hi
ดังนี้
message Rectangle {
// One corner of the rectangle.
Point lo = 1;
// The other corner of the rectangle.
Point hi = 2;
}
นอกจากนี้ ยังมีข้อความ RouteNote
ที่แสดงถึงข้อความที่ส่งขณะอยู่ที่จุดหนึ่งๆ ด้วย
message RouteNote {
// The location from which the message is sent.
Point location = 1;
// The message to be sent.
string message = 2;
}
สุดท้าย คุณจะต้องมีRouteSummary
ข้อความ คุณจะได้รับข้อความนี้เป็นการตอบกลับ RPC ของ RecordRoute
ซึ่งจะอธิบายในส่วนถัดไป โดยจะมีจำนวนจุดแต่ละจุดที่ได้รับ จำนวนฟีเจอร์ที่ตรวจพบ และระยะทางทั้งหมดที่ครอบคลุมเป็นผลรวมสะสมของระยะทางระหว่างแต่ละจุด
message RouteSummary {
// The number of points received.
int32 point_count = 1;
// The number of known features passed while traversing the route.
int32 feature_count = 2;
// The distance covered in metres.
int32 distance = 3;
// The duration of the traversal in seconds.
int32 elapsed_time = 4;
}
กำหนดวิธีการบริการ
หากต้องการกำหนดบริการ ให้ระบุบริการที่มีชื่อในไฟล์ .proto
ไฟล์ route_guide.proto
มีโครงสร้าง service
ชื่อ RouteGuide
ซึ่งกำหนดวิธีการอย่างน้อย 1 วิธีที่บริการของแอปพลิเคชันมีให้
เมื่อกำหนดRPC
เมธอดภายในคำจำกัดความของบริการ คุณจะระบุประเภทคำขอและการตอบกลับของเมธอดเหล่านั้น ในส่วนนี้ของโค้ดแล็บ เราจะกำหนดค่าต่อไปนี้
ListFeatures
รับออบเจ็กต์ Feature
ที่มีอยู่ภายใน Rectangle
ที่ระบุ ระบบจะสตรีมผลการค้นหาแทนที่จะแสดงผลทั้งหมดในครั้งเดียว เนื่องจากสี่เหลี่ยมผืนผ้าอาจครอบคลุมพื้นที่ขนาดใหญ่และมีฟีเจอร์จำนวนมาก
สำหรับแอปพลิเคชันนี้ คุณจะใช้ RPC แบบสตรีมมิงฝั่งเซิร์ฟเวอร์ ซึ่งไคลเอ็นต์จะส่งคำขอไปยังเซิร์ฟเวอร์และรับสตรีมเพื่ออ่านลำดับข้อความกลับ ไคลเอ็นต์จะอ่านจากสตรีมที่ส่งคืนจนกว่าจะไม่มีข้อความเหลือ ดังที่เห็นในตัวอย่าง คุณระบุวิธีการสตรีมฝั่งเซิร์ฟเวอร์ได้โดยวางคีย์เวิร์ดสตรีมไว้ก่อนประเภทการตอบกลับ
rpc ListFeatures(Rectangle) returns (stream Feature) {}
RecordRoute
ยอมรับสตรีมของจุดในเส้นทางที่กำลังเดินทาง และส่งคืน RouteSummary
เมื่อการเดินทางเสร็จสมบูรณ์
ในกรณีนี้ RPC การสตรีมฝั่งไคลเอ็นต์จะเหมาะสม โดยไคลเอ็นต์จะเขียนลำดับข้อความและส่งไปยังเซิร์ฟเวอร์อีกครั้งโดยใช้สตรีมที่ระบุ เมื่อไคลเอ็นต์เขียนข้อความเสร็จแล้ว ไคลเอ็นต์จะรอให้เซิร์ฟเวอร์อ่านข้อความทั้งหมดและส่งการตอบกลับ คุณระบุวิธีการสตรีมฝั่งไคลเอ็นต์ได้โดยวางคีย์เวิร์ดสตรีมไว้ก่อนประเภทคำขอ
rpc RecordRoute(stream Point) returns (RouteSummary) {}
RouteChat
ยอมรับสตรีมของ RouteNotes
ที่ส่งขณะที่กำลังเดินทางตามเส้นทาง ขณะเดียวกันก็รับ RouteNotes
อื่นๆ (เช่น จากผู้ใช้รายอื่น)
นี่คือกรณีการใช้งานที่เหมาะกับการสตรีมแบบ 2 ทาง RPC แบบสตรีมมิงแบบ 2 ทางซึ่งทั้ง 2 ฝ่ายจะส่งลำดับข้อความโดยใช้สตรีมแบบอ่าน-เขียน สตรีมทั้ง 2 รายการทำงานแยกกัน ดังนั้นไคลเอ็นต์และเซิร์ฟเวอร์จึงอ่านและเขียนได้ตามลำดับที่ต้องการ เช่น เซิร์ฟเวอร์อาจรอรับข้อความทั้งหมดจากไคลเอ็นต์ก่อนที่จะเขียนการตอบกลับ หรืออาจอ่านข้อความแล้วเขียนข้อความสลับกัน หรืออาจใช้การอ่านและการเขียนแบบอื่นๆ ระบบจะรักษลําดับของข้อความในแต่ละสตรีมไว้ คุณระบุประเภทเมธอดนี้ได้โดยวางคีย์เวิร์ดสตรีมไว้ก่อนทั้งคำขอและการตอบกลับ
rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
4. สร้างโค้ดไคลเอ็นต์และเซิร์ฟเวอร์
จากนั้นสร้างโค้ด gRPC มาตรฐานสำหรับทั้งไคลเอ็นต์และเซิร์ฟเวอร์จากไฟล์ .proto
โดยใช้คอมไพเลอร์ Protocol Buffer
เราได้สร้าง grpcio-tools สำหรับการสร้างโค้ด gRPC Python แอปประกอบด้วย
- คอมไพเลอร์ protoc ปกติที่สร้างโค้ด Python จากคำจำกัดความ
message
- ปลั๊กอิน Protobuf ของ gRPC ที่สร้างโค้ด Python (ต้นขั้วไคลเอ็นต์และเซิร์ฟเวอร์) จาก
service
เราจะติดตั้งgrpcio-tools
แพ็กเกจ Python โดยใช้ pip มาสร้างสภาพแวดล้อมเสมือนของ Python (venv) ใหม่เพื่อแยกการอ้างอิงของโปรเจ็กต์ออกจากแพ็กเกจของระบบกัน
python3 -m venv --upgrade-deps .venv
วิธีเปิดใช้งานสภาพแวดล้อมเสมือนใน Bash/Zsh Shell
source .venv/bin/activate
สำหรับ Windows และเชลล์ที่ไม่ใช่แบบมาตรฐาน โปรดดูตารางที่ https://docs.python.org/3/library/venv.html#how-venvs-work
จากนั้นติดตั้ง grpcio-tools (ซึ่งจะติดตั้งแพ็กเกจ grpcio ด้วย)
pip install grpcio-tools
ใช้คำสั่งต่อไปนี้เพื่อสร้างโค้ดบอยเลอร์เพลต Python
python -m grpc_tools.protoc --proto_path=./protos \
--python_out=. --pyi_out=. --grpc_python_out=. \
./protos/route_guide.proto
การดำเนินการนี้จะสร้างไฟล์ต่อไปนี้สำหรับอินเทอร์เฟซที่เรากำหนดไว้ใน route_guide.proto
route_guide_pb2.py
มีโค้ดที่สร้างคลาสแบบไดนามิกซึ่งสร้างจากคำจำกัดความของmessage
route_guide_pb2.pyi
คือ "ไฟล์ Stub" หรือ "ไฟล์คำแนะนำประเภท" ที่สร้างจากคำจำกัดความของmessage
โดยจะมีเฉพาะลายเซ็นที่ไม่มีการติดตั้งใช้งาน IDE สามารถใช้ไฟล์ Stub เพื่อให้การเติมข้อความอัตโนมัติและการตรวจหาข้อผิดพลาดดียิ่งขึ้นroute_guide_pb2_grpc.py
สร้างขึ้นจากคำจำกัดความของservice
และมีคลาสและฟังก์ชันเฉพาะของ gRPC
โค้ดเฉพาะ gRPC มีดังนี้
RouteGuideStub
ซึ่งไคลเอ็นต์ gRPC สามารถใช้เพื่อเรียกใช้ RPC ของ RouteGuide ได้RouteGuideServicer
ซึ่งกำหนดอินเทอร์เฟซสำหรับการใช้งานบริการRouteGuide
add_RouteGuideServicer_to_server
ฟังก์ชันที่ใช้เพื่อลงทะเบียนRouteGuideServicer
กับ เซิร์ฟเวอร์ gRPC
5. สร้างเซิร์ฟเวอร์
ก่อนอื่นมาดูวิธีสร้างRouteGuide
เซิร์ฟเวอร์กัน การสร้างและเรียกใช้RouteGuide
เซิร์ฟเวอร์แบ่งออกเป็น 2 รายการงาน ดังนี้
- การติดตั้งใช้งานอินเทอร์เฟซผู้ให้บริการที่สร้างขึ้นจากคำจำกัดความของบริการของเราด้วยฟังก์ชันที่ทำ "งาน" จริงของบริการ
- การเรียกใช้เซิร์ฟเวอร์ gRPC เพื่อรอรับคำขอจากไคลเอ็นต์และส่งการตอบกลับ
มาดูที่ route_guide_server.py
กัน
ใช้ RouteGuide
route_guide_server.py
มีคลาส RouteGuideServicer
ที่เป็นคลาสย่อยของคลาส route_guide_pb2_grpc.RouteGuideServicer
ที่สร้างขึ้น
# RouteGuideServicer provides an implementation of the methods of the RouteGuide service.
class RouteGuideServicer(route_guide_pb2_grpc.RouteGuideServicer):
RouteGuideServicer
จะใช้เมธอดบริการทั้งหมดของ RouteGuide
RPC การสตรีมฝั่งเซิร์ฟเวอร์
ListFeatures
เป็น RPC การสตรีมการตอบกลับที่ส่ง Feature
หลายรายการไปยังไคลเอ็นต์
def ListFeatures(self, request, context):
"""List all features contained within the given Rectangle."""
left = min(request.lo.longitude, request.hi.longitude)
right = max(request.lo.longitude, request.hi.longitude)
top = max(request.lo.latitude, request.hi.latitude)
bottom = min(request.lo.latitude, request.hi.latitude)
for feature in self.db:
lat, lng = feature.location.latitude, feature.location.longitude
if left <= lng <= right and bottom <= lat <= top:
yield feature
ในที่นี้ ข้อความคำขอคือ route_guide_pb2.Rectangle
ซึ่งไคลเอ็นต์ต้องการค้นหา Feature
เมธอดนี้จะให้คำตอบ 0 รายการขึ้นไปแทนที่จะให้คำตอบรายการเดียว
RPC การสตรีมฝั่งไคลเอ็นต์
เมธอดการสตรีมคำขอ RecordRoute
ใช้ Iterator ของค่าคำขอและแสดงผลค่าการตอบกลับเดียว
def RecordRoute(self, request_iterator, context):
"""Calculate statistics about the trip composed of Points."""
point_count = 0
feature_count = 0
distance = 0.0
prev_point = None
start_time = time.time()
for point in request_iterator:
point_count += 1
if get_feature(self.db, point):
feature_count += 1
if prev_point:
distance += get_distance(prev_point, point)
prev_point = point
elapsed_time = time.time() - start_time
return route_guide_pb2.RouteSummary(
point_count=point_count,
feature_count=feature_count,
distance=int(distance),
elapsed_time=int(elapsed_time),
)
RPC การสตรีมแบบ 2 ทิศทาง
สุดท้าย มาดู RPC แบบสตรีมแบบ 2 ทาง RouteChat()
def RouteChat(self, request_iterator, context):
"""
Receive a stream of message/location pairs, and responds with
a stream of all previous messages for the given location.
"""
prev_notes = []
for new_note in request_iterator:
for prev_note in prev_notes:
if prev_note.location == new_note.location:
yield prev_note
prev_notes.append(new_note)
ความหมายของเมธอดนี้เป็นการรวมกันของเมธอดการสตรีมคำขอและเมธอดการสตรีมการตอบกลับ โดยจะส่งค่าตัววนซ้ำของค่าคำขอ และตัวมันเองก็เป็นตัววนซ้ำของค่าการตอบกลับ
เริ่มเซิร์ฟเวอร์
เมื่อใช้RouteGuide
เมธอดทั้งหมดแล้ว ขั้นตอนถัดไปคือการเริ่มต้นเซิร์ฟเวอร์ gRPC เพื่อให้ไคลเอ็นต์ใช้บริการของคุณได้จริง
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
route_guide_pb2_grpc.add_RouteGuideServicer_to_server(
RouteGuideServicer(),
server,
)
listen_addr = "localhost:50051"
server.add_insecure_port(listen_addr)
print(f"Starting server on {listen_addr}")
server.start()
server.wait_for_termination()
เมธอดเซิร์ฟเวอร์ start()
จะไม่บล็อก ระบบจะสร้างเธรดใหม่เพื่อจัดการคำขอ โดยปกติแล้ว เธรดที่เรียก server.start()
จะไม่มีงานอื่นใดให้ทำในระหว่างนี้ ในกรณีนี้ คุณสามารถเรียกใช้ server.wait_for_termination()
เพื่อบล็อกเธรดการโทรอย่างสมบูรณ์จนกว่าเซิร์ฟเวอร์จะสิ้นสุด
6. สร้างไคลเอ็นต์
มาดูที่ route_guide_client.py
กัน
สร้าง Stub
หากต้องการเรียกใช้เมธอดของบริการ เราต้องสร้างสตับก่อน
เราสร้างอินสแตนซ์ของRouteGuideStub
คลาสของโมดูล route_guide_pb2_grpc
ที่สร้างขึ้นจากเมธอด .proto.
In run()
ดังนี้
with grpc.insecure_channel("localhost:50051") as channel:
stub = route_guide_pb2_grpc.RouteGuideStub(channel)
โปรดทราบว่าในที่นี้ channel
ใช้เป็นตัวจัดการบริบท และจะปิดโดยอัตโนมัติเมื่ออินเทอร์พรีเตอร์ออกจากบล็อก with
วิธีการเรียกใช้บริการ
สำหรับเมธอด RPC ที่ส่งคืนการตอบกลับรายการเดียว (เมธอด "response-unary") gRPC Python รองรับทั้งซีแมนทิกส์ของโฟลว์การควบคุมแบบซิงโครนัส (การบล็อก) และแบบไม่พร้อมกัน (การไม่บล็อก) สำหรับเมธอด RPC ที่สตรีมการตอบกลับ การเรียกจะแสดงผลตัววนซ้ำของค่าการตอบกลับทันที การเรียกใช้เมธอด next()
ของตัววนซ้ำนั้นจะบล็อกจนกว่าการตอบกลับที่จะส่งคืนจากตัววนซ้ำจะพร้อมใช้งาน
RPC การสตรีมฝั่งเซิร์ฟเวอร์
การเรียกใช้การสตรีมการตอบกลับ ListFeatures
จะคล้ายกับการทำงานกับประเภทลำดับ
def guide_list_features(stub):
_lo = route_guide_pb2.Point(latitude=400000000, longitude=-750000000)
_hi = route_guide_pb2.Point(latitude=420000000, longitude=-730000000)
rectangle = route_guide_pb2.Rectangle(
lo=_lo,
hi=_hi,
)
print("Looking for features between 40, -75 and 42, -73")
features = stub.ListFeatures(rectangle)
for feature in features:
print(
f"Feature called '{feature.name}'"
f" at {format_point(feature.location)}"
)
RPC การสตรีมฝั่งไคลเอ็นต์
การเรียกใช้การสตรีมคำขอ RecordRoute
จะคล้ายกับการส่งผ่านตัววนซ้ำไปยังเมธอดในเครื่อง เช่นเดียวกับ RPC อย่างง่ายข้างต้นที่ส่งคืนการตอบกลับรายการเดียว คุณสามารถเรียกใช้แบบซิงโครนัสได้ดังนี้
def guide_record_route(stub):
feature_list = route_guide_resources.read_route_guide_database()
route_iterator = generate_route(feature_list)
route_summary = stub.RecordRoute(route_iterator)
print(f"Finished trip with {route_summary.point_count} points")
print(f"Passed {route_summary.feature_count} features")
print(f"Traveled {route_summary.distance} meters")
print(f"It took {route_summary.elapsed_time} seconds")
RPC การสตรีมแบบ 2 ทิศทาง
การเรียกใช้ RouteChat
แบบสตรีมแบบสองทิศทางจะมี (เช่นเดียวกับในฝั่งบริการ) การผสมผสานระหว่างความหมายของสตรีมมิงคำขอและสตรีมมิงการตอบกลับ
สร้างข้อความคำขอ แล้วส่งทีละข้อความโดยใช้ yield
def generate_notes():
home = route_guide_pb2.Point(latitude=1, longitude=1)
work = route_guide_pb2.Point(latitude=2, longitude=2)
notes = [
make_route_note("Departing from home", home),
make_route_note("Arrived at work", work),
make_route_note("Having lunch at work", work),
make_route_note("Departing from work", work),
make_route_note("Arrived home", home),
]
for note in notes:
print(
f"Sending RouteNote for {format_point(note.location)}:"
f" {note.message}"
)
yield note
# Sleep to simulate moving from one point to another.
# Only for demonstrating the order of the messages.
time.sleep(0.1)
รับและประมวลผลการตอบกลับของเซิร์ฟเวอร์
def guide_route_chat(stub):
responses = stub.RouteChat(generate_notes())
for response in responses:
print(
"< Found previous note at"
f" {format_point(response.location)}: {response.message}"
)
เรียกใช้เมธอดตัวช่วย
ในฟังก์ชัน run ให้เรียกใช้เมธอดที่เราเพิ่งสร้างขึ้น และส่ง stub
ไปยังเมธอดเหล่านั้น
print("-------------- ListFeatures --------------")
guide_list_features(stub)
print("-------------- RecordRoute --------------")
guide_record_route(stub)
print("-------------- RouteChat --------------")
guide_route_chat(stub)
7. ลองเลย
เรียกใช้เซิร์ฟเวอร์
python route_guide_server.py
จากเทอร์มินัลอื่น ให้เปิดใช้งานสภาพแวดล้อมเสมือนอีกครั้ง (source .venv/bin/activate)
) แล้วเรียกใช้ไคลเอ็นต์โดยใช้คำสั่งต่อไปนี้
python route_guide_client.py
มาดูเอาต์พุตกัน
ListFeatures
ก่อนอื่น คุณจะเห็นรายการฟีเจอร์ ระบบจะสตรีมแต่ละฟีเจอร์จากเซิร์ฟเวอร์ (RPC การสตรีมฝั่งเซิร์ฟเวอร์) เมื่อพบว่าฟีเจอร์นั้นอยู่ภายในสี่เหลี่ยมผืนผ้าที่ขอ
-------------- ListFeatures -------------- Looking for features between 40, -75 and 42, -73 Feature called 'Patriots Path, Mendham, NJ 07945, USA' at (lat=407838351, lng=-746143763) Feature called '101 New Jersey 10, Whippany, NJ 07981, USA' at (lat=408122808, lng=-743999179) Feature called 'U.S. 6, Shohola, PA 18458, USA' at (lat=413628156, lng=-749015468) Feature called '5 Conners Road, Kingston, NY 12401, USA' at (lat=419999544, lng=-740371136) ...
RecordRoute
ประการที่ 2 RecordRoute
แสดงรายการจุดที่เข้าชมแบบสุ่มซึ่งสตรีมจากไคลเอ็นต์ไปยังเซิร์ฟเวอร์ (RPC การสตรีมฝั่งไคลเอ็นต์)
-------------- RecordRoute -------------- Visiting point (lat=410395868, lng=-744972325) Visiting point (lat=404310607, lng=-740282632) Visiting point (lat=403966326, lng=-748519297) Visiting point (lat=407586880, lng=-741670168) Visiting point (lat=406589790, lng=-743560121) Visiting point (lat=410322033, lng=-747871659) Visiting point (lat=415464475, lng=-747175374) Visiting point (lat=407586880, lng=-741670168) Visiting point (lat=402647019, lng=-747071791) Visiting point (lat=414638017, lng=-745957854)
หลังจากไคลเอ็นต์สตรีมจุดที่เข้าชมทั้งหมดเสร็จแล้ว ไคลเอ็นต์จะได้รับการตอบกลับแบบไม่สตรีม (RPC แบบเอกภาค) จากเซิร์ฟเวอร์ คำตอบนี้จะมีสรุปการคำนวณที่ดำเนินการในเส้นทางแบบเต็มของไคลเอ็นต์
Finished trip with 10 points Passed 10 features Traveled 654743 meters It took 0 seconds
RouteChat
สุดท้าย RouteChat
เอาต์พุตแสดงให้เห็นการสตรีมแบบ 2 ทาง เมื่อไคลเอ็นต์ "เยี่ยมชม" จุด home
หรือ work
ไคลเอ็นต์จะบันทึกหมายเหตุสำหรับจุดดังกล่าวโดยส่ง RouteNote ไปยังเซิร์ฟเวอร์ เมื่อมีการเข้าชมจุดหนึ่งแล้ว เซิร์ฟเวอร์จะสตรีมโน้ตก่อนหน้าทั้งหมดสำหรับจุดนี้กลับมา
-------------- RouteChat -------------- Sending RouteNote for (lat=1, lng=1): Departing from home Sending RouteNote for (lat=2, lng=2): Arrived at work Sending RouteNote for (lat=2, lng=2): Having lunch at work < Found previous note at (lat=2, lng=2): Arrived at work Sending RouteNote for (lat=2, lng=2): Departing from work < Found previous note at (lat=2, lng=2): Arrived at work < Found previous note at (lat=2, lng=2): Having lunch at work Sending RouteNote for (lat=1, lng=1): Arrived home < Found previous note at (lat=1, lng=1): Departing from home
8. ขั้นตอนถัดไป
- ดูวิธีการทำงานของ gRPC ในข้อมูลเบื้องต้นเกี่ยวกับ gRPC และแนวคิดหลัก
- ดูบทแนะนำเกี่ยวกับพื้นฐาน
- สำรวจข้อมูลอ้างอิงของ Python API