0Pricing
C Academy · درس

معالجة عدة عملاء

select وpoll

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

مشكلة التزامن

يعالج الخادم البسيط عميلًا واحدًا في كل مرة. فإذا كان أحد العملاء بطيئًا، ينتظر الآخرون جميعًا. ولخدمة عدد كبير من العملاء بالتزامن، تحتاجون إلى نموذج مختلف.

أساليب التزامن

ثلاث استراتيجيات شائعة:

  • خيط أو عملية لكل عميل: بسيطة، لكنها تستهلك موارد كثيرة عند التوسع
  • تعدد إرسال الإدخال/الإخراج باستخدام select أو poll: يراقب خيط واحد مقابس كثيرة
  • حلقات الأحداث باستخدام epoll/kqueue: تتوسع إلى آلاف الاتصالات

ما الذي يفعله select

تراقب select() مجموعة من واصفات الملفات، وتخبركم بأيّها جاهز للقراءة أو الكتابة، أو يحتوي على أخطاء، وذلك كله في استدعاء واحد حاجب. يتيح هذا لخيط واحد خدمة مقابس كثيرة.

أساسيات fd_set

يستخدم select قناع البتات fd_set. وأديروه باستخدام وحدات الماكرو: FD_ZERO وFD_SET وFD_CLR وFD_ISSET.

#include <sys/select.h>

void setup_set(fd_set *set, int listen_fd) {
    FD_ZERO(set);          /* clear all */
    FD_SET(listen_fd, set); /* watch the listener */
}

استدعاء select

يحتاج select إلى أكبر fd مضافًا إليه واحد، ويعدّل المجموعة مباشرةً لوضع علامة على الواصفات الجاهزة. ولأنه يغيّر المجموعة، يجب إعادة بنائها قبل كل استدعاء.

#include <sys/select.h>
#include <stdio.h>

int wait_ready(int maxfd, fd_set *read_set) {
    int n = select(maxfd + 1, read_set, NULL, NULL, NULL);
    if (n < 0) perror("select");
    return n; /* number of ready fds */
}

حلقة خادم select

النمط المتّبع هو: إعادة بناء المجموعة، ثم استدعاء select، وبعد ذلك معالجة كل fd جاهز؛ فإما قبول عميل جديد إذا كان هو المستمع، أو قراءة البيانات إذا كان عميلًا.

#include <sys/select.h>

void loop_skeleton(int listen_fd, fd_set *master, int maxfd) {
    fd_set work;
    for (;;) {
        work = *master;           /* copy, select destroys it */
        select(maxfd + 1, &work, NULL, NULL, NULL);
        for (int fd = 0; fd <= maxfd; fd++) {
            if (!FD_ISSET(fd, &work)) continue;
            /* fd == listen_fd -> accept; else -> recv */
        }
    }
}

تتبّع العملاء

عند قبول اتصال جديد، أضيفوا fd الخاص به إلى المجموعة الرئيسية وحدّثوا maxfd. وعندما ينقطع العميل (يعيد recv القيمة 0)، أغلقوه باستخدام close وأزيلوه من المجموعة باستخدام FD_CLR.

#include <sys/select.h>
#include <unistd.h>

void add_client(fd_set *master, int *maxfd, int conn) {
    FD_SET(conn, master);
    if (conn > *maxfd) *maxfd = conn;
}
void drop_client(fd_set *master, int conn) {
    close(conn);
    FD_CLR(conn, master);
}

حدود select

لدى select بعض العيوب:

  • يقتصر على واصفات FD_SETUP (غالبًا 1024)
  • يفحص جميع fd في كل استدعاء بزمن O(n)
  • تُعاد بناء المجموعة في كل تكرار

بالنسبة إلى الاتصالات الكثيرة، يتوسع poll أو epoll بصورة أفضل.

ما الذي يقدمه poll

يتلقى poll() مصفوفة من struct pollfd بدلًا من قناع بتات ثابت، ولذلك لا يفرض حدًا يبلغ 1024 واصفًا، ولا يتلف الإدخال في كل استدعاء.

#include <poll.h>

void setup_poll(struct pollfd *pfd, int listen_fd) {
    pfd[0].fd = listen_fd;
    pfd[0].events = POLLIN; /* notify when readable */
}

استدعاء poll

يحجب poll التنفيذ حتى يصبح fd واحد على الأقل جاهزًا (أو تنتهي المهلة)، ثم يضبط revents في كل إدخال جاهز.

#include <poll.h>
#include <stdio.h>

int poll_ready(struct pollfd *pfds, int count) {
    int n = poll(pfds, count, -1); /* -1 = block forever */
    if (n < 0) perror("poll");
    return n;
}

التوسع: epoll

بالنسبة إلى آلاف الاتصالات، يعيد epoll في Linux (وkqueue في BSD) واصفات الملفات الجاهزة فقط بزمن O(1) لكل حدث، متجنبًا الفحص الكامل الذي ينفذه select وpoll.

تحقّق سريع

اختبر مدى فهمك للتعامل مع عدة عملاء.

مراجعة

تعلّمتم خدمة عدة عملاء باستخدام خيط واحد.

  • يراقب select عدة fd؛ وأديروها باستخدام وحدات الماكرو FD_
  • أعيدوا بناء المجموعة في كل حلقة لأن select يغيّرها
  • أضيفوا العملاء المقبولين إلى المجموعة، وأزيلوهم عند انقطاع الاتصال
  • يتجنب poll حد 1024، بينما يتوسع epoll إلى آلاف الاتصالات

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

هل درس «معالجة عدة عملاء» مجاني؟

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

ماذا ستتعلم في «معالجة عدة عملاء»؟

select وpoll تتمرن على C Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ C Academy؟

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

كم من الوقت يستغرق درس «معالجة عدة عملاء»؟

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

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

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

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

  1. نظرة عامة على المقابس
  2. خادم TCP
  3. عميل TCP
  4. معالجة عدة عملاء
← العودة إلى C Academy