gRPC-Python का इस्तेमाल शुरू करना - स्ट्रीमिंग

1. परिचय

इस कोडलैब में, gRPC-Python का इस्तेमाल करके एक क्लाइंट और सर्वर बनाया जाएगा. ये दोनों, Python में लिखे गए रूट-मैपिंग ऐप्लिकेशन की बुनियादी ज़रूरतें पूरी करते हैं.

ट्यूटोरियल के आखिर तक, आपके पास एक ऐसा क्लाइंट होगा जो gRPC का इस्तेमाल करके, रिमोट सर्वर से कनेक्ट होता है. इससे क्लाइंट के रूट पर मौजूद सुविधाओं के बारे में जानकारी मिलती है, क्लाइंट के रूट की खास जानकारी बनाई जाती है, और सर्वर और अन्य क्लाइंट के साथ रूट की जानकारी शेयर की जाती है. जैसे, ट्रैफ़िक अपडेट.

सेवा को प्रोटोकॉल बफ़र फ़ाइल में तय किया जाता है. इसका इस्तेमाल क्लाइंट और सर्वर के लिए बॉयलरप्लेट कोड जनरेट करने के लिए किया जाएगा, ताकि वे एक-दूसरे से कम्यूनिकेट कर सकें. इससे आपको उस सुविधा को लागू करने में समय और मेहनत नहीं करनी पड़ेगी.

जनरेट किया गया यह कोड, सर्वर और क्लाइंट के बीच कम्यूनिकेशन की जटिलताओं के साथ-साथ डेटा के क्रमबद्ध और क्रम से हटाने की प्रोसेस को भी मैनेज करता है.

आपको क्या सीखने को मिलेगा

  • किसी सेवा के एपीआई को तय करने के लिए, प्रोटोकॉल बफ़र का इस्तेमाल कैसे करें.
  • ऑटोमेटेड कोड जनरेशन का इस्तेमाल करके, Protocol Buffers की परिभाषा से gRPC पर आधारित क्लाइंट और सर्वर बनाने का तरीका.
  • gRPC के साथ क्लाइंट-सर्वर स्ट्रीमिंग कम्यूनिकेशन के बारे में जानकारी.

यह कोडलैब, Python डेवलपर के लिए है. यह उन लोगों के लिए भी है जो gRPC का इस्तेमाल पहली बार कर रहे हैं या gRPC के बारे में फिर से जानकारी पाना चाहते हैं. इसके अलावा, यह उन लोगों के लिए भी है जिनकी दिलचस्पी डिस्ट्रिब्यूटेड सिस्टम बनाने में है. इसके लिए, gRPC का अनुभव होना ज़रूरी नहीं है.

2. शुरू करने से पहले

आपको किन चीज़ों की ज़रूरत होगी

  • Python 3.9 या इसके बाद का वर्शन. हमारा सुझाव है कि Python 3.13 का इस्तेमाल करें. प्लेटफ़ॉर्म के हिसाब से इंस्टॉल करने के निर्देशों के लिए, Python Setup and Usage देखें. इसके अलावा, uv या pyenv जैसे टूल का इस्तेमाल करके, सिस्टम के बाहर का Python इंस्टॉल करें.
  • Python पैकेज इंस्टॉल करने के लिए, pip का इस्तेमाल करें.
  • Python वर्चुअल एनवायरमेंट बनाने के लिए, venv का इस्तेमाल करें.

ensurepip और venv पैकेज, Python स्टैंडर्ड लाइब्रेरी का हिस्सा हैं. ये आम तौर पर डिफ़ॉल्ट रूप से उपलब्ध होते हैं.

हालांकि, Debian पर आधारित कुछ डिस्ट्रिब्यूशन (जैसे, Ubuntu) Python को फिर से डिस्ट्रिब्यूट करते समय, इन्हें शामिल नहीं करते. पैकेज इंस्टॉल करने के लिए, यह कमांड चलाएं:

sudo apt install python3-pip python3-venv

कोड प्राप्त करें

इस कोडलैब में, पहले से बना हुआ सोर्स कोड स्केफ़ोल्ड उपलब्ध है. इससे आपको शुरुआत करने में मदद मिलेगी. यहां दिए गए चरणों से, आपको आवेदन पूरा करने में मदद मिलेगी. इसमें grpc_tools.protoc प्रोटोकॉल बफ़र कंपाइलर प्लगिन का इस्तेमाल करके gRPC कोड जनरेट करना भी शामिल है.

grpc-codelabs

इस कोडलैब के लिए, स्कैफ़ोल्ड सोर्स कोड codelabs/grpc-python-streaming/start_here डायरेक्ट्री में उपलब्ध है. अगर आपको कोड खुद लागू नहीं करना है, तो पूरा सोर्स कोड completed डायरेक्ट्री में उपलब्ध है.

सबसे पहले, कोडलैब की वर्किंग डायरेक्ट्री बनाएं और उसमें cd करें:

mkdir grpc-python-streaming && cd grpc-python-streaming

कोडलैब को डाउनलोड और एक्सट्रैक्ट करें:

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 फ़ाइल डाउनलोड करके, उसे मैन्युअल तरीके से अनज़िप किया जा सकता है.

3. संदेशों और सेवाओं के बारे में जानकारी

सबसे पहले, आपको प्रोटोकॉल बफ़र का इस्तेमाल करके, ऐप्लिकेशन की gRPC सेवा, उसके आरपीसी तरीके, और उसके अनुरोध और जवाब के मैसेज टाइप तय करने होंगे. आपकी सेवा से ये सुविधाएं मिलेंगी:

  • सर्वर लागू करता है और क्लाइंट कॉल करता है, जिन्हें RPC तरीके ListFeatures, RecordRoute, और RouteChat कहा जाता है.
  • मैसेज टाइप Point, Feature, Rectangle, RouteNote, और RouteSummary, जो आरपीसी तरीकों को कॉल करते समय क्लाइंट और सर्वर के बीच एक्सचेंज किए गए डेटा स्ट्रक्चर होते हैं.

ये सभी आरपीसी तरीके और उनके मैसेज टाइप, दिए गए सोर्स कोड की protos/route_guide.proto फ़ाइल में तय किए जाएंगे.

प्रोटोकॉल बफ़र को आम तौर पर, protobufs के नाम से जाना जाता है. gRPC की शब्दावली के बारे में ज़्यादा जानने के लिए, gRPC के मुख्य कॉन्सेप्ट, आर्किटेक्चर, और लाइफ़साइकल देखें.

मैसेज टाइप तय करना

सोर्स कोड की protos/route_guide.proto फ़ाइल में, सबसे पहले Point मैसेज टाइप तय करें. Point, मैप पर अक्षांश-देशांतर के निर्देशांकों के जोड़े को दिखाता है. इस कोडलैब के लिए, पूर्णांकों का इस्तेमाल करें:

message Point {
  int32 latitude = 1;
  int32 longitude = 2;
}

1 और 2 नंबर, message स्ट्रक्चर में मौजूद हर फ़ील्ड के लिए यूनीक आईडी नंबर होते हैं.

इसके बाद, Feature मैसेज टाइप तय करें. Feature, Point में बताई गई जगह पर मौजूद किसी चीज़ के नाम या डाक पते के लिए string फ़ील्ड का इस्तेमाल करता है:

message Feature {
  // The name or address of the feature.
  string name = 1;

  // The point where the feature is located.
  Point location = 2;
}

किसी इलाके के कई पॉइंट को क्लाइंट को स्ट्रीम करने के लिए, आपको Rectangle मैसेज की ज़रूरत होगी. यह मैसेज, अक्षांश-देशांतर वाले आयत को दिखाता है. इसे दो विकर्ण विपरीत पॉइंट 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 मैसेज की ज़रूरत होगी. यह मैसेज, 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 होता है. यह ऐप्लिकेशन की सेवा के ज़रिए उपलब्ध कराए गए एक या उससे ज़्यादा तरीकों के बारे में बताता है.

सेवा की परिभाषा में RPC तरीके तय करते समय, उनके अनुरोध और जवाब के टाइप तय किए जाते हैं. इस कोडलैब के इस सेक्शन में, हम इन चीज़ों के बारे में जानेंगे:

ListFeatures

यह फ़ंक्शन, दिए गए Rectangle में मौजूद Feature ऑब्जेक्ट को हासिल करता है. नतीजे एक साथ नहीं दिखाए जाते, बल्कि स्ट्रीम किए जाते हैं. ऐसा इसलिए, क्योंकि रेक्टैंगल में बहुत बड़ा इलाका शामिल हो सकता है और इसमें कई सुविधाएं हो सकती हैं.

इस ऐप्लिकेशन के लिए, सर्वर-साइड स्ट्रीमिंग आरपीसी का इस्तेमाल किया जाएगा: क्लाइंट, सर्वर को अनुरोध भेजता है और उसे मैसेज का क्रम वापस पढ़ने के लिए एक स्ट्रीम मिलती है. क्लाइंट, जवाब के तौर पर मिली स्ट्रीम से तब तक डेटा पढ़ता है, जब तक कोई और मैसेज नहीं मिलता. हमारे उदाहरण में दिखाया गया है कि रिस्पॉन्स टाइप से पहले स्ट्रीम कीवर्ड रखकर, सर्वर-साइड स्ट्रीमिंग के तरीके के बारे में बताया जाता है.

rpc ListFeatures(Rectangle) returns (stream Feature) {}

RecordRoute

यह फ़ंक्शन, तय किए गए रास्ते पर मौजूद पॉइंट की स्ट्रीम को स्वीकार करता है. साथ ही, रास्ता पूरा होने पर RouteSummary दिखाता है.

इस मामले में, क्लाइंट-साइड स्ट्रीमिंग आरपीसी सही है: क्लाइंट, मैसेज का क्रम लिखता है और उन्हें सर्वर को भेजता है. इसके लिए, वह उपलब्ध स्ट्रीम का फिर से इस्तेमाल करता है. क्लाइंट के मैसेज लिखने के बाद, वह सर्वर के उन सभी मैसेज को पढ़ने और जवाब देने का इंतज़ार करता है. क्लाइंट-साइड स्ट्रीमिंग के तरीके के बारे में बताने के लिए, स्ट्रीम कीवर्ड को अनुरोध के टाइप से पहले रखा जाता है.

rpc RecordRoute(stream Point) returns (RouteSummary) {}

RouteChat

यह कुकी, रास्ते पर चलते समय भेजे गए RouteNotes की स्ट्रीम को स्वीकार करती है. साथ ही, अन्य RouteNotes (जैसे, अन्य उपयोगकर्ताओं से मिले RouteNotes) को भी स्वीकार करती है.

दोनों दिशाओं में स्ट्रीमिंग का इस्तेमाल इसी तरह के मामलों में किया जाता है. यह दोनों दिशाओं में स्ट्रीम करने वाला आरपीसी है. इसमें दोनों पक्ष, पढ़ने और लिखने की स्ट्रीम का इस्तेमाल करके मैसेज का क्रम भेजते हैं. ये दोनों स्ट्रीम अलग-अलग काम करती हैं. इसलिए, क्लाइंट और सर्वर अपनी पसंद के हिसाब से किसी भी क्रम में पढ़ और लिख सकते हैं. उदाहरण के लिए, सर्वर अपने जवाब लिखने से पहले, क्लाइंट के सभी मैसेज पाने का इंतज़ार कर सकता है. इसके अलावा, वह बारी-बारी से एक मैसेज पढ़ सकता है और फिर एक मैसेज लिख सकता है. इसके अलावा, वह पढ़ने और लिखने के किसी अन्य कॉम्बिनेशन का इस्तेमाल कर सकता है. हर स्ट्रीम में मैसेज का क्रम बना रहता है. इस तरह के तरीके को तय करने के लिए, अनुरोध और जवाब, दोनों से पहले स्ट्रीम कीवर्ड रखा जाता है.

rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}

4. क्लाइंट और सर्वर कोड जनरेट करना

इसके बाद, प्रोटोकॉल बफ़र कंपाइलर का इस्तेमाल करके, .proto फ़ाइल से क्लाइंट और सर्वर, दोनों के लिए बॉयलरप्लेट gRPC कोड जनरेट करें.

gRPC Python कोड जनरेट करने के लिए, हमने grpcio-tools बनाया है. इसमें ये चीज़ें शामिल हैं:

  1. यह एक सामान्य protoc कंपाइलर है, जो message डेफ़िनिशन से Python कोड जनरेट करता है.
  2. gRPC प्रोटॉबफ़ प्लगिन, जो service डेफ़िनिशन से Python कोड (क्लाइंट और सर्वर स्टब) जनरेट करता है.

हम pip का इस्तेमाल करके, grpcio-tools Python पैकेज इंस्टॉल करेंगे. अपने प्रोजेक्ट की डिपेंडेंसी को सिस्टम पैकेज से अलग करने के लिए, चलिए एक नया Python वर्चुअल एनवायरमेंट (venv) बनाते हैं:

python3 -m venv --upgrade-deps .venv

bash/zsh शेल में वर्चुअल एनवायरमेंट को चालू करने के लिए:

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 में तय किए गए इंटरफ़ेस के लिए, ये फ़ाइलें जनरेट होंगी:

  1. route_guide_pb2.py में ऐसा कोड होता है जो क्लास को डाइनैमिक तरीके से बनाता है. यह कोड, message की परिभाषाओं से जनरेट होता है.
  2. route_guide_pb2.pyi, message की परिभाषाओं से जनरेट की गई "स्टब फ़ाइल" या "टाइप हिंट फ़ाइल" है. इसमें सिर्फ़ ऐसे सिग्नेचर होते हैं जिन्हें लागू नहीं किया गया है. आईडीई, स्टब फ़ाइलों का इस्तेमाल करके, अपने-आप पूरा होने वाली सुविधा को बेहतर बना सकते हैं. साथ ही, गड़बड़ियों का पता लगा सकते हैं.
  3. route_guide_pb2_grpc.py, service की परिभाषाओं से जनरेट होता है. इसमें gRPC से जुड़ी क्लास और फ़ंक्शन शामिल होते हैं.

gRPC के लिए खास तौर पर बनाए गए कोड में ये शामिल हैं:

  1. RouteGuideStub, जिसका इस्तेमाल gRPC क्लाइंट, RouteGuide RPC को शुरू करने के लिए कर सकता है.
  2. RouteGuideServicer, जो RouteGuide सेवा को लागू करने के लिए इंटरफ़ेस तय करता है.
  3. add_RouteGuideServicer_to_server फ़ंक्शन का इस्तेमाल, gRPC सर्वर पर RouteGuideServicer को रजिस्टर करने के लिए किया जाता है.

5. सर्वर बनाना

सबसे पहले, देखते हैं कि RouteGuide सर्वर कैसे बनाया जाता है. RouteGuide सर्वर बनाने और उसे चलाने के लिए, दो काम करने होते हैं:

  • हमारी सेवा की परिभाषा से जनरेट किए गए सर्विसर इंटरफ़ेस को लागू करना. इसमें ऐसे फ़ंक्शन शामिल होते हैं जो सेवा का असल "काम" करते हैं.
  • क्लाइंट से मिले अनुरोधों को सुनने और जवाब भेजने के लिए, 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 सेवा के सभी तरीकों को लागू करता है.

सर्वर-साइड स्ट्रीमिंग आरपीसी

ListFeatures एक रिस्पॉन्स-स्ट्रीमिंग आरपीसी है. यह क्लाइंट को कई 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 है, जिसमें क्लाइंट को Features ढूंढने हैं. यह तरीका, एक जवाब देने के बजाय कोई जवाब नहीं देता या एक से ज़्यादा जवाब देता है.

क्लाइंट-साइड स्ट्रीमिंग आरपीसी

अनुरोध-स्ट्रीमिंग वाला तरीका RecordRoute, अनुरोध की वैल्यू के इटरेटर का इस्तेमाल करता है और जवाब की एक वैल्यू दिखाता है.

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),
    )

दोनों दिशाओं में डेटा स्ट्रीम करने वाला आरपीसी

आखिर में, आइए हम दोनों दिशाओं में डेटा ट्रांसफ़र करने वाले आरपीसी 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 पर एक नज़र डालें.

स्टब बनाना

सेवा के तरीकों को कॉल करने के लिए, हमें सबसे पहले एक स्टब बनाना होगा.

हम route_guide_pb2_grpc मॉड्यूल की RouteGuideStub क्लास को इंस्टैंशिएट करते हैं. यह run() तरीके से हमारे .proto. से जनरेट होता है:

with grpc.insecure_channel("localhost:50051") as channel:
    stub = route_guide_pb2_grpc.RouteGuideStub(channel)

ध्यान दें कि यहां channel का इस्तेमाल कॉन्टेक्स्ट मैनेजर के तौर पर किया गया है. इंटरप्रेटर के with ब्लॉक से बाहर निकलने के बाद, यह अपने-आप बंद हो जाएगा.

कॉल सेवा के तरीके

एक जवाब ("response-unary" तरीके) देने वाले आरपीसी तरीकों के लिए, gRPC Python, कंट्रोल फ़्लो सिमैंटिक्स के सिंक्रोनस (ब्लॉकिंग) और एसिंक्रोनस (नॉन-ब्लॉकिंग), दोनों को सपोर्ट करता है. रिस्पॉन्स-स्ट्रीमिंग आरपीसी तरीकों के लिए, कॉल तुरंत रिस्पॉन्स वैल्यू का इटरेटर दिखाता है. उस इटरेटर के next() तरीके को कॉल करने पर, तब तक ब्लॉक किया जाता है, जब तक इटरेटर से मिलने वाला जवाब उपलब्ध नहीं हो जाता.

सर्वर-साइड स्ट्रीमिंग आरपीसी

जवाब को स्ट्रीम करने वाले 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)}"
        )

क्लाइंट-साइड स्ट्रीमिंग आरपीसी

अनुरोध-स्ट्रीमिंग RecordRoute को कॉल करना, किसी लोकल तरीके को इटरेटर पास करने जैसा होता है. ऊपर दिए गए सामान्य आरपीसी की तरह, यह भी एक ही जवाब देता है. इसे सिंक्रोनस तरीके से कॉल किया जा सकता है:

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")

दोनों दिशाओं में डेटा स्ट्रीम करने वाला आरपीसी

दोनों दिशाओं में स्ट्रीम करने वाली 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

सबसे पहले, आपको सुविधाओं की सूची दिखेगी. हर सुविधा को सर्वर से स्ट्रीम किया जाता है (सर्वर-साइड स्ट्रीमिंग आरपीसी). ऐसा तब किया जाता है, जब सुविधा को अनुरोध किए गए रेक्टैंगल में खोजा जाता है:

-------------- 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

दूसरे, RecordRoute में, क्लाइंट से सर्वर पर स्ट्रीम किए गए, रैंडम तरीके से विज़िट किए गए पॉइंट की सूची दिखाई गई है (क्लाइंट-साइड स्ट्रीमिंग आरपीसी):

-------------- 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)

क्लाइंट के सभी विज़िट किए गए पॉइंट स्ट्रीम करने के बाद, उसे सर्वर से नॉन-स्ट्रीमिंग रिस्पॉन्स (एक यूनेरी आरपीसी) मिलेगा. इस जवाब में, क्लाइंट के पूरे रूट पर की गई कैलकुलेशन की खास जानकारी शामिल होगी.

Finished trip with 10 points
Passed 10 features
Traveled 654743 meters
It took 0 seconds

RouteChat

आखिर में, RouteChat आउटपुट में दोनों दिशाओं में स्ट्रीम होने वाली सुविधा के बारे में बताया गया है. जब क्लाइंट, 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. आगे क्या करना है