الاستدعاء من عميل gRPC
استهلك الخدمة
الاستدعاء من عميل gRPC درس مجاني في Learn Rust Coding على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Learn Rust Coding، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Learn Rust Coding 4 دروس في المجموع.
العميل المُولَّد
لكل خدمة، تُولّد tonic بنية عميل، مثل GreeterClient، داخل الوحدة greeter_client. وتوفّر هذه البنية أسلوباً غير متزامن واحداً لكل rpc.
يمكنك إنشاؤها من قناة نقل أو عبر الاتصال مباشرةً بنقطة نهاية.
use greeter::v1::greeter_client::GreeterClient;
use greeter::v1::HelloRequest;الاتصال بخادم
أبسط طريقة هي استخدام GreeterClient::connect، الذي يستقبل سلسلة عنوان ويُرجع عميلاً متصلاً.
يعمل هذا داخل سياق غير متزامن، لذا استدعِه تحت #[tokio::main] مع .await.
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = GreeterClient::connect("http://[::1]:50051").await?;
Ok(())
}إجراء استدعاء أحادي
غلّف رسالتك داخل tonic::Request، أو استخدم Request::new، ثم استدعِ الأسلوب المُولَّد.
الاستجابة هي tonic::Response؛ استدعِ .into_inner() لقراءة الرسالة.
let request = tonic::Request::new(HelloRequest { name: "Ada".into() });
let response = client.say_hello(request).await?;
println!("{}", response.into_inner().message);التعامل مع أخطاء Status
إذا أعاد الخادم خطأً، فستُرجع العملية Err(Status). افحص status.code() وstatus.message() لاتخاذ الإجراء المناسب.
يشبه ذلك جانب الخادم: إذ تنتقل رموز مثل NotFound أو Unauthenticated إلى العميل.
match client.say_hello(req).await {
Ok(resp) => println!("{}", resp.into_inner().message),
Err(status) => eprintln!("{}: {}", status.code(), status.message()),
}بناء قناة
لإعادة الاستخدام والتهيئة، ابنِ كائن Channel صراحةً باستخدام Endpoint. يمكنك ضبط المهلات، وإبقاء اتصال TCP نشطاً، وخيارات الاتصال.
بعد ذلك أنشئ العميل باستخدام GreeterClient::new(channel).
use tonic::transport::{Channel, Endpoint};
let channel = Endpoint::from_static("http://[::1]:50051")
.timeout(std::time::Duration::from_secs(5))
.connect()
.await?;
let mut client = GreeterClient::new(channel);إرسال البيانات الوصفية
أرفق ترويسات مثل رموز المصادقة بإدراجها في البيانات الوصفية للطلب قبل إرساله.
استخدم MetadataValue للقيمة؛ إذ يجب أن تكون قيمة ترويسة ASCII صالحة.
use tonic::metadata::MetadataValue;
let mut req = tonic::Request::new(HelloRequest { name: "Ada".into() });
let token: MetadataValue<_> = "Bearer abc123".parse()?;
req.metadata_mut().insert("authorization", token);المواعيد النهائية لكل استدعاء
حدّد موعداً نهائياً حتى لا يتسبب خادم بطيء في تعليق العميل. يؤدي set_timeout في الطلب إلى إلغائه بحالة DeadlineExceeded عند تجاوز المدة.
تنتقل المواعيد النهائية إلى الخادم، الذي يستطيع إيقاف العمل مبكراً.
let mut req = tonic::Request::new(HelloRequest { name: "Ada".into() });
req.set_timeout(std::time::Duration::from_secs(2));
let resp = client.say_hello(req).await?;استهلاك تدفق من الخادم
يُرجع استدعاء البث من الخادم تدفقاً. احصل عليه باستخدام into_inner() واسحب الرسائل باستعمال message().await داخل حلقة إلى أن يُرجع None.
تمنحك كل دورة استجابةً واحدةً مفككة الترميز.
let mut stream = client.server_stream(req).await?.into_inner();
while let Some(item) = stream.message().await? {
println!("{:?}", item);
}البث من العميل
في استدعاء البث من العميل، مرّر تدفقاً غير متزامن من الطلبات. غلّف مكرراً أو قناة باستخدام tokio_stream ومرّره إلى الأسلوب.
تصل الاستجابة الوحيدة بعد إتمامك إرسال الطلبات.
use tokio_stream::iter;
let outbound = iter(vec![msg1, msg2, msg3]);
let response = client.client_stream(Request::new(outbound)).await?;
println!("{:?}", response.into_inner());اتصالات TLS
للنقل المشفّر، هيّئ ClientTlsConfig بشهادة CA ونطاق الخادم، ثم اتصل عبر https.
يتطلب ذلك تفعيل ميزة tls في الاعتمادية tonic.
use tonic::transport::{ClientTlsConfig, Endpoint};
let tls = ClientTlsConfig::new().domain_name("example.com");
let channel = Endpoint::from_static("https://example.com:50051")
.tls_config(tls)?
.connect()
.await?;إعادة استخدام العميل
إن Channel الأساسي قليل التكلفة عند استنساخه، ويعدّد الطلبات عبر اتصال HTTP/2 واحد. استنسخ العميل بين المهام بدلاً من إعادة الاتصال.
يحافظ ذلك على انخفاض تكلفة إعداد الاتصال عند العمل بالتوازي.
let client = GreeterClient::new(channel);
let mut c1 = client.clone();
let mut c2 = client.clone();
// use c1 and c2 in separate tokio tasksتحقق سريع
كيف تقرأ نتيجة استدعاء عميل أحادي في tonic؟
مراجعة
لقد اتصلت بعميل مُولَّد، وأجريت استدعاءات أحادية، وتعاملت مع أخطاء Status، وبنيت قنوات مهيّأة، وأرسلت بيانات وصفية، وحددت مواعيد نهائية، واستهلكت تدفقات الخادم والعميل، وفعّلت TLS، وأعدت استخدام عملاء منخفضي التكلفة عند استنساخهم.
يمكنك الآن بناء خدمات gRPC كاملة قائمة على tonic من البداية إلى النهاية.
الأسئلة الشائعة
هل درس «الاستدعاء من عميل gRPC» مجاني؟
نعم — نص درس «الاستدعاء من عميل gRPC» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Learn Rust Coding، انتقل إلى CoddyKit PRO. تتضمن دورة Learn Rust Coding 4 دروس في المجموع.
ماذا ستتعلم في «الاستدعاء من عميل gRPC»؟
استهلك الخدمة تتمرن على Learn Rust Coding مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Learn Rust Coding؟
لا تُشترط خبرة سابقة. Learn Rust Coding على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.
كم من الوقت يستغرق درس «الاستدعاء من عميل gRPC»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Learn Rust Coding هذا؟
نعم. كل درس في Learn Rust Coding يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- تعريفات Protobuf والخدمات
- إنشاء الشيفرة باستخدام tonic-build
- تنفيذ خادم gRPC
- الاستدعاء من عميل gRPC