0Pricing
Learn Rust Coding · درس

تنفيذ خادم gRPC

قدّم أساليب RPC أحادية الطلب

تنفيذ خادم gRPC درس مجاني في Learn Rust Coding على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Learn Rust Coding، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Learn Rust Coding 4 دروس في المجموع.

سمة الخادم المولَّدة

بالنسبة إلى خدمة تُسمّى Greeter، يولّد tonic سمة داخل greeter_server. وتطبّقونها على بنية خاصة بكم لتوفير السلوك.

السمة async عبر #[tonic::async_trait]، لذلك تكون كل طريقة دالة غير متزامنة تُعيد Result.

use greeter::v1::greeter_server::{Greeter, GreeterServer};
use greeter::v1::{HelloRequest, HelloReply};

أغلفة الطلب والاستجابة

تتلقى الطرق tonic::Request<T> وتعيد tonic::Response<T>. وتحمل هذه الأغلفة البيانات الوصفية والامتدادات والرسالة الداخلية.

استدعوا .into_inner() للحصول على الرسالة المفككة، واستخدموا Response::new(..) لإنشاء رد.

let req: HelloRequest = request.into_inner();
let reply = HelloReply { message: format!("Hi {}", req.name) };
Ok(Response::new(reply))

بنية الخادم

عرّفوا بنية للاحتفاظ بأي حالة مشتركة، مثل مجموعة اتصالات قاعدة البيانات. وغالبًا ما ترث Default عندما تكون بلا حالة.

ستطبّقون السمة المولَّدة على هذه البنية.

#[derive(Default)]
pub struct MyGreeter {}

تطبيق طريقة أحادية

ضعوا التعليق التوضيحي على كتلة impl باستخدام #[tonic::async_trait]، وطبّقوا كل rpc بوصفها دالة غير متزامنة تطابق التوقيع المولَّد.

أعيدوا Ok(Response::new(reply)) عند النجاح.

#[tonic::async_trait]
impl Greeter for MyGreeter {
    async fn say_hello(&self, request: Request<HelloRequest>)
        -> Result<Response<HelloReply>, Status> {
        let name = request.into_inner().name;
        Ok(Response::new(HelloReply { message: format!("Hello {name}") }))
    }
}

إعادة الأخطاء باستخدام Status

تُعاد الأخطاء بوصفها tonic::Status، التي تُطابق رمز حالة gRPC. استخدموا منشئات مثل Status::invalid_argument أو Status::not_found.

تُرسل سلسلة الرسالة إلى العميل إلى جانب الرمز.

if name.is_empty() {
    return Err(Status::invalid_argument("name must not be empty"));
}

البناء والتقديم

استخدموا tonic::transport::Server داخل main غير متزامنة. أضيفوا خدمتكم مغلّفة في نوع ...Server المولَّد، ثم استدعوا serve مع عنوان مقبس.

يوفّر الماكرو #[tokio::main] بيئة التشغيل.

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let addr = "[::1]:50051".parse()?;
    Server::builder()
        .add_service(GreeterServer::new(MyGreeter::default()))
        .serve(addr)
        .await?;
    Ok(())
}

استجابات البث من الخادم

تعيد طريقة البث من الخادم نوع بث. يستخدم tonic نوعًا مرتبطًا بالإضافة إلى بث مغلّف؛ وتُعدّ قناة mpsc طريقة شائعة لتغذية الرسائل.

أعيدوا ReceiverStream مغلّفًا داخل Response.

use tokio_stream::wrappers::ReceiverStream;
let (tx, rx) = tokio::sync::mpsc::channel(8);
tokio::spawn(async move { tx.send(Ok(reply)).await.ok(); });
Ok(Response::new(ReceiverStream::new(rx)))

قراءة البيانات الوصفية

تحتوي البيانات الوصفية للطلب على ترويسات مثل رموز المصادقة. يمكنكم الوصول إليها باستخدام request.metadata() قبل استهلاك النص الأساسي.

المفاتيح ASCII وغير حساسة لحالة الأحرف؛ وتُعاد القيم بوصفها MetadataValue.

if let Some(token) = request.metadata().get("authorization") {
    // validate token
} else {
    return Err(Status::unauthenticated("missing token"));
}

المعترضات

يعمل المعترض قبل كل طلب، وهو مثالي للمصادقة أو التسجيل. ويتلقى Request ويعيده أو يعيد خطأ Status.

أرفقوه باستخدام with_interceptor عند إضافة الخدمة.

fn auth(req: Request<()>) -> Result<Request<()>, Status> {
    match req.metadata().get("authorization") {
        Some(_) => Ok(req),
        None => Err(Status::unauthenticated("no token")),
    }
}
// .add_service(GreeterServer::with_interceptor(svc, auth))

الإيقاف السلس

استخدموا serve_with_shutdown لإيقاف قبول الاتصالات عندما تُحسم future، مثل إشارة Ctrl-C.

تكتمل الطلبات الجارية قبل خروج الخادم، مما يتجنب إسقاطها فجأة.

Server::builder()
    .add_service(GreeterServer::new(MyGreeter::default()))
    .serve_with_shutdown(addr, async {
        tokio::signal::ctrl_c().await.ok();
    })
    .await?;

الحالة المشتركة

لمشاركة حالة قابلة للتعديل بين الطلبات، خزّنوها خلف Arc وبدائِي تزامن مثل tokio::sync::Mutex داخل بنية الخادم.

ينسخ tonic الخدمة لكل اتصال، لذا فإن المقابض المشتركة الرخيصة النسخ هي النمط المناسب.

use std::sync::Arc;
use tokio::sync::Mutex;

#[derive(Default)]
pub struct MyGreeter {
    hits: Arc<Mutex<u64>>,
}

تحقق سريع

كيف تُبلّغ طرق gRPC عن حالات الفشل في tonic؟

مراجعة

لقد طبّقت trait الخادم المُولَّد: فكّ تغليف الطلبات، وإرجاع الاستجابات وأخطاء Status، وتشغيل الخدمة باستخدام tokio، وبثّ الاستجابات، وقراءة البيانات الوصفية، وإضافة المعترضات، والإيقاف السلس، ومشاركة الحالة عبر Arc.

ستبني بعد ذلك عميلاً لاستدعاء هذا الخادم.

الأسئلة الشائعة

هل درس «تنفيذ خادم gRPC» مجاني؟

نعم — نص درس «تنفيذ خادم gRPC» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Learn Rust Coding، انتقل إلى CoddyKit PRO. تتضمن دورة Learn Rust Coding 4 دروس في المجموع.

ماذا ستتعلم في «تنفيذ خادم gRPC»؟

قدّم أساليب RPC أحادية الطلب تتمرن على Learn Rust Coding مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Learn Rust Coding؟

لا تُشترط خبرة سابقة. Learn Rust Coding على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.

كم من الوقت يستغرق درس «تنفيذ خادم gRPC»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Learn Rust Coding هذا؟

نعم. كل درس في Learn Rust Coding يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. تعريفات Protobuf والخدمات
  2. إنشاء الشيفرة باستخدام tonic-build
  3. تنفيذ خادم gRPC
  4. الاستدعاء من عميل gRPC
← العودة إلى Learn Rust Coding