1. مقدمة
في هذا الدرس العملي، ستستخدم gRPC-Python لإنشاء عميل وخادم يشكّلان أساس تطبيق لربط المسارات مكتوب بلغة Python.
في نهاية هذا البرنامج التعليمي، سيكون لديك تطبيق عميل يتصل بخادم بعيد باستخدام gRPC للحصول على اسم أو عنوان بريدي للموقع الجغرافي الذي يقع عند إحداثيات معيّنة على الخريطة. قد يستخدم تطبيق متكامل تصميم العميل والخادم هذا لتعداد نقاط الاهتمام أو تلخيصها على طول مسار معيّن.
يتم تحديد الخدمة في ملف Protocol Buffers، وسيتم استخدام هذا الملف لإنشاء رمز نموذجي للبرنامج العميل والخادم حتى يتمكّنا من التواصل مع بعضهما البعض، ما يوفّر عليك الوقت والجهد في تنفيذ هذه الوظيفة.
لا يهتم هذا الرمز الذي تم إنشاؤه بتعقيدات الاتصال بين الخادم والعميل فحسب، بل أيضًا بتسلسل البيانات وإلغاء تسلسلها.
أهداف الدورة التعليمية
- كيفية استخدام مخزن البروتوكولات المؤقت لتحديد واجهة برمجة تطبيقات الخدمة
- كيفية إنشاء برنامج عميل وخادم يستندان إلى gRPC من تعريف Protocol Buffers باستخدام إنشاء الرموز البرمجية المبرمَج
- فهم عملية التواصل بين العميل والخادم باستخدام gRPC
هذا الدرس التطبيقي حول الترميز مخصّص لمطوّري Python الجدد على gRPC أو الذين يريدون مراجعة gRPC، أو أي شخص آخر مهتم بإنشاء أنظمة موزّعة. لا يُشترط توفّر خبرة سابقة في gRPC.
2. قبل البدء
المتطلبات
- الإصدار 3.9 أو الإصدارات الأحدث من Python ننصح باستخدام الإصدار 3.13 من Python. للحصول على تعليمات التثبيت الخاصة بكل نظام أساسي، يُرجى الاطّلاع على إعداد Python واستخدامه. بدلاً من ذلك، ثبِّت إصدارًا غير تابع للنظام من Python باستخدام أدوات مثل uv أو pyenv.
- pip لتثبيت حِزم Python
- venv لإنشاء بيئات Python افتراضية
الحزمتان ensurepip
وvenv
هما جزء من مكتبة Python العادية، وتتوفّران عادةً بشكل تلقائي.
ومع ذلك، تختار بعض التوزيعات المستندة إلى Debian (بما في ذلك Ubuntu) استبعادها عند إعادة توزيع Python. لتثبيت الحِزم، نفِّذ ما يلي:
sudo apt install python3-pip python3-venv
الحصول على الشفرة
لتبسيط عملية التعلّم، يوفّر لك هذا الدرس التطبيقي حول الترميز بنية رمز مصدر مُنشأة مسبقًا لمساعدتك على البدء. ستساعدك الخطوات التالية في إكمال الطلب، بما في ذلك إنشاء رمز gRPC باستخدام grpc_tools.protoc
مكوّن إضافي لمترجم Protocol Buffer.
grpc-codelabs
يتوفّر رمز المصدر الخاص بالدرس التطبيقي حول الترميز في الدليل codelabs/grpc-python-getting-started/start_here. إذا كنت تفضّل عدم تنفيذ الرمز بنفسك، يتوفّر رمز المصدر المكتمل في الدليل completed
.
أولاً، أنشئ دليل عمل الدرس التطبيقي وادخله:
mkdir grpc-python-getting-started && cd grpc-python-getting-started
نزِّل الدرس التطبيقي حول الترميز واستخرِجه:
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-getting-started/start_here
بدلاً من ذلك، يمكنك تنزيل ملف .zip الذي يحتوي على دليل الدرس العملي فقط وفك ضغطه يدويًا.
3- تحديد الخدمة
تتمثّل خطوتك الأولى في تحديد خدمة gRPC للتطبيق وطريقة استدعاء الإجراء عن بُعد وأنواع رسائل الطلبات والاستجابات باستخدام لغة تعريف الواجهة لمخزن البروتوكولات المؤقت. ستوفّر خدمتك ما يلي:
- طريقة استدعاء إجراء عن بُعد (RPC) تُسمّى
GetFeature
ينفّذها الخادم ويستدعيها العميل. - نوعا الرسائل
Point
وFeature
هما بنى بيانات يتم تبادلها بين العميل والخادم عند استخدام الطريقةGetFeature
. يقدّم العميل إحداثيات الخريطة كـPoint
في طلبGetFeature
إلى الخادم، ويردّ الخادم بـFeature
مطابق يصف أي شيء يقع في تلك الإحداثيات.
سيتم تحديد طريقة RPC هذه وأنواع الرسائل الخاصة بها في ملف protos/route_guide.proto
الخاص برمز المصدر المقدَّم.
يُعرف Protocol Buffers باسم protobuf. لمزيد من المعلومات عن مصطلحات gRPC، يُرجى الاطّلاع على المفاهيم الأساسية والبنية ودورة الحياة في gRPC.
أنواع الرسائل
في ملف protos/route_guide.proto
الخاص بالرمز المصدر، حدِّد أولاً نوع الرسالة Point
. يمثّل Point
زوج إحداثيات خط العرض وخط الطول على الخريطة. في هذا الدرس العملي، استخدِم أعدادًا صحيحة للإحداثيات:
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;
}
طريقة الخدمة
يحتوي ملف route_guide.proto
على بنية service
باسم RouteGuide
تحدّد طريقة واحدة أو أكثر توفّرها خدمة التطبيق.
أضِف الطريقة rpc
داخل تعريف RouteGuide
.GetFeature
كما هو موضّح سابقًا، ستبحث هذه الطريقة عن اسم أو عنوان موقع جغرافي من مجموعة إحداثيات معيّنة، لذا اطلب من GetFeature
عرض Feature
لـ Point
معيّن:
service RouteGuide {
// Definition of the service goes here
// Obtains the feature at a given position.
rpc GetFeature(Point) returns (Feature) {}
}
هذه طريقة أحادية لاستدعاء الإجراء عن بُعد: استدعاء إجراء بسيط عن بُعد يرسل فيه العميل طلبًا إلى الخادم وينتظر تلقّي ردّ، تمامًا مثل استدعاء دالة محلية.
4. إنشاء رمز العميل والخادم
بعد ذلك، أنشئ رمز gRPC النموذجي لكل من البرنامج الخادم والبرنامج العميل من ملف .proto
باستخدام برنامج تجميع مخزن البروتوكولات المؤقت.
لإنشاء رمز Python في gRPC، أنشأنا grpcio-tools. ويشمل ذلك:
- برنامج التجميع العادي protoc الذي ينشئ رمز Python من تعريفات
message
- مكوّن إضافي لبروتوكول gRPC protobuf ينشئ رمز Python (طرق كعب العميل والخادم) من تعريفات
service
.
سنثبّت حزمة grpcio-tools
Python باستخدام pip. لننشئ بيئة افتراضية جديدة بلغة Python (venv) لعزل تبعيات مشروعك عن حِزم النظام:
python3 -m venv --upgrade-deps .venv
لتفعيل البيئة الافتراضية في shell 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
:
- يحتوي
route_guide_pb2.py
على الرمز الذي ينشئ الفئات بشكل ديناميكي من تعريفاتmessage
. route_guide_pb2.pyi
هو "ملف فارغ" أو "ملف تلميح النوع" تم إنشاؤه من تعريفاتmessage
. يحتوي فقط على التواقيع بدون تنفيذ. يمكن أن تستخدم بيئات التطوير المتكاملة ملفات Stub لتوفير ميزة الإكمال التلقائي ورصد الأخطاء بشكل أفضل.- يتم إنشاء
route_guide_pb2_grpc.py
من تعريفاتservice
ويحتوي على فئات ودوال خاصة بـ gRPC.
يتضمّن الرمز البرمجي الخاص بـ gRPC ما يلي:
5- إنشاء الخدمة
لنبدأ بالاطّلاع على كيفية إنشاء خادم RouteGuide
. ينقسم إنشاء خادم RouteGuide
وتشغيله إلى عنصرَي عمل:
- تنفيذ واجهة مقدّم الخدمة التي تم إنشاؤها من تعريف الخدمة باستخدام وظائف تنفّذ "العمل" الفعلي للخدمة
- تشغيل خادم gRPC على منفذ محدّد للاستماع إلى الطلبات من العملاء وإرسال الردود
يمكنك العثور على خادم RouteGuide
الأوّلي في start_here/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 بالتفصيل. تحصل الطريقة GetFeature
على Point
من العميل وتعرض معلومات الميزة المطابقة من قاعدة البيانات في Feature
.
def GetFeature(self, request, context):
feature = get_feature(self.db, request)
if feature is None:
return route_guide_pb2.Feature(name="", location=request)
else:
return feature
يتم تمرير route_guide_pb2.Point
طلب إلى الطريقة لإجراء استدعاء إجراء عن بُعد، بالإضافة إلى كائن grpc.ServicerContext
يوفّر معلومات خاصة باستدعاء الإجراء عن بُعد، مثل حدود المهلة. ويعرض الرد route_guide_pb2.Feature
.
بدء الخادم
بعد تنفيذ جميع طرق 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. إنشاء العميل
في هذا القسم، سنتعرّف على كيفية إنشاء برنامج لخدمة RouteGuide
. يمكنك الاطّلاع على رمز العميل الأوّلي في start_here/route_guide_client.py
.
إنشاء مقالة موجزة
لاستدعاء طرق الخدمة، يجب أولاً إنشاء رمز بديل.
ننشئ مثيلاً لفئة RouteGuideStub
من الوحدة route_guide_pb2_grpc
، التي تم إنشاؤها من .proto
داخل الملف route_guide_client.py
.
channel = grpc.insecure_channel("localhost:50051")
stub = route_guide_pb2_grpc.RouteGuideStub(channel)
طُرق الاتصال بالخدمة
بالنسبة إلى طرق RPC التي تعرض استجابة واحدة، والمعروفة باسم طرق response-unary، يتيح gRPC Python دلالات التحكّم المتزامنة (الحظر) وغير المتزامنة (عدم الحظر) في سير العمل.
Simple RPC
أولاً، لنحدّد Point
لاستخدامه في طلب الخدمة. يجب أن يكون ذلك بسيطًا مثل إنشاء مثيل لكائن من حزمة route_guide_pb2
مع بعض السمات:
point = route_guide_pb2.Point(latitude=412346009, longitude=-744026814)
إنّ إجراء مكالمة متزامنة إلى RPC البسيط GetFeature
لا يختلف كثيرًا عن استدعاء طريقة محلية. ينتظر طلب RPC استجابة الخادم، وسيعرض إما استجابة أو سيحدث استثناء. يمكننا استدعاء الطريقة والاطّلاع على الردّ على النحو التالي:
feature = stub.GetFeature(point)
print(feature)
يمكنك فحص حقول عنصر Feature وعرض نتيجة الطلب:
if feature.name:
print(f"Feature called '{feature.name}' at {format_point(feature.location)}")
else:
print(f"Found no feature at at {format_point(feature.location)}")
7. جرّبه الآن
شغِّل الخادم:
python route_guide_server.py
من وحدة طرفية مختلفة، فعِّل البيئة الافتراضية مرة أخرى، ثم شغِّل العميل:
python route_guide_client.py
ستظهر لك نتيجة مشابهة لما يلي، مع حذف الطوابع الزمنية لتوضيح الصورة:
name: "16 Old Brook Lane, Warwick, NY 10990, USA" location { latitude: 412346009 longitude: -744026814 } Feature called '16 Old Brook Lane, Warwick, NY 10990, USA' at latitude: 412346009, longitude: -744026814
8. الخطوات التالية
- تعرَّف على طريقة عمل gRPC في مقدمة عن gRPC والمفاهيم الأساسية
- اتّبِع الخطوات الواردة في الدليل التعليمي الخاص بالأساسيات
- استكشاف مرجع Python API