recvmmsg(2)

الاسم
recvmmsg - استقبال رسائل متعددة على مقبس

المكتبة
مكتبة سي المعيارية (libc، -lc)

موجز
#define _GNU_SOURCE         /* انظر feature_test_macros(7) */
#include <sys/socket.h>

int recvmmsg(unsigned int n;
             int sockfd, struct mmsghdr msgvec[n], unsigned int n,
             int flags, struct timespec *timeout);

الوصف
استدعاء النظام recvmmsg() هو امتداد لـ recvmsg(2) يسمح للمستدعي باستقبال رسائل متعددة من مقبس باستخدام استدعاء نظام واحد. (هذا يوفر فوائد أداء لبعض التطبيقات.) امتداد إضافي على recvmsg(2) هو دعم مهلة زمنية لعملية الاستقبال.

الوسيط sockfd هو واصف الملف للمقبس الذي سيتم استقبال البيانات منه.

المعامل msgvec هو مؤشر لمصفوفة من هياكل mmsghdr. حُدد حجم هذه المصفوفة في n.

عُرف هيكل mmsghdr في <sys/socket.h> كالتالي:

    struct mmsghdr {
        struct msghdr msg_hdr;  /* Message header */
        unsigned int  msg_len;  /* Number of received bytes for header */
    };

الحقل msg_hdr هو بنية msghdr، كما هو موصوف في recvmsg(2). الحقل msg_len هو عدد البايتات المعادة للرسالة في الإدخال. هذا الحقل له نفس قيمة القيمة المعادة لاستدعاء recvmsg(2) واحد على الرأس.

الوسيط flags يحتوي على أعلام مدمجة بعملية OR. الأعلام هي نفسها الموثقة لـ recvmsg(2)، مع الإضافة التالية:

MSG_WAITFORONE (منذ لينكس 2.6.34)
    يقوم بتشغيل MSG_DONTWAIT بعد استقبال الرسالة الأولى.

الوسيط timeout يشير إلى struct timespec (انظر clock_gettime(2)) يحدد مهلة زمنية (ثوانٍ بالإضافة إلى نانوثوانٍ) لعملية الاستقبال (لكن انظر الأخطاء!). (سيتم تقريب هذه الفترة إلى دقة ساعة النظام، وتأخيرات جدولة النواة تعني أن فترة الحظر قد تتجاوز بمقدار صغير.) إذا كان timeout هو NULL، فإن العملية تحظر إلى أجل غير مسمى.

استدعاء recvmmsg() المحظور يحظر حتى يتم استقبال n رسالة أو حتى تنتهي المهلة. الاستدعاء غير المحظور يقرأ أكبر عدد ممكن من الرسائل المتاحة (حتى الحد المحدد بواسطة n) ويعود فورًا.

عند العودة من recvmmsg()، يتم تحديث العناصر المتتالية من msgvec لتحتوي على معلومات حول كل رسالة مستلمة: msg_len يحتوي على حجم الرسالة المستلمة؛ الحقول الفرعية لـ msg_hdr يتم تحديثها كما هو موصوف في recvmsg(2). القيمة المعادة للاستدعاء تشير إلى عدد عناصر msgvec التي تم تحديثها.

قيمة الإرجاع
عند النجاح، يعيد recvmmsg() عدد الرسائل المستلمة في msgvec؛ عند الخطأ، يتم إرجاع -1، ويتم تعيين errno للإشارة إلى الخطأ.

الأخطاء
الأخطاء هي كما في recvmsg(2). بالإضافة إلى ذلك، يمكن أن يحدث الخطأ التالي:

EINVAL
    timeout غير صالح.

انظر أيضًا الأخطاء.

المعايير
لينكس.

التاريخ
لينكس 2.6.33، glibc 2.12.

العلل
الوسيط timeout لا يعمل كما هو مقصود. يتم التحقق من المهلة فقط بعد استقبال كل مخطط بيانات، بحيث إذا تم استقبال ما يصل إلى n-1 مخطط بيانات قبل انتهاء المهلة، ولكن بعد ذلك لم يتم استقبال أي مخططات بيانات أخرى، فإن الاستدعاء سيحظر إلى الأبد.

إذا حدث خطأ بعد استقبال رسالة واحدة على الأقل، فإن الاستدعاء ينجح، ويعيد عدد الرسائل المستلمة. من المتوقع إعادة رمز الخطأ في استدعاء لاحق لـ recvmmsg(). ومع ذلك، في التنفيذ الحالي، يمكن استبدال رمز الخطأ في هذه الأثناء بواسطة حدث شبكة غير مرتبط على مقبس، على سبيل المثال حزمة ICMP واردة.

أمثلة
البرنامج التالي يستخدم recvmmsg() لاستقبال رسائل متعددة على مقبس ويخزنها في مخازن متعددة. يعود الاستدعاء إذا تم ملء جميع المخازن أو إذا انتهت المهلة المحددة.

المقتطف التالي يولد بشكل دوري مخططات بيانات UDP تحتوي على رقم عشوائي:

    $ while true; do echo $RANDOM > /dev/udp/127.0.0.1/1234;
    sleep 0.25; done

تتم قراءة هذه المخططات بواسطة التطبيق المثال، والذي يمكن أن يعطي المخرجات التالية:

    $ ./a.out
    5 messages received
    1 11782
    2 11345
    3 304
    4 13514
    5 28421

  مصدر البرنامج
    #define _GNU_SOURCE
    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <time.h>

    int
    main(void)
    {
    #define VLEN 10
    #define BUFSIZE 200
    #define TIMEOUT 1
        int                 sockfd, retval;
        char                bufs[VLEN][BUFSIZE+1];
        struct iovec        iovecs[VLEN];
        struct mmsghdr      msgs[VLEN];
        struct timespec     timeout;
        struct sockaddr_in  addr;

        sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (sockfd == -1) {
            perror("socket()");
            exit(EXIT_FAILURE);
        }

        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
        addr.sin_port = htons(1234);
        if (bind(sockfd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
            perror("bind()");
            exit(EXIT_FAILURE);
        }

        memset(msgs, 0, sizeof(msgs));
        for (size_t i = 0; i < VLEN; i++) {
            iovecs[i].iov_base         = bufs[i];
            iovecs[i].iov_len          = BUFSIZE;
            msgs[i].msg_hdr.msg_iov    = &iovecs[i];
            msgs[i].msg_hdr.msg_iovlen = 1;
        }

        timeout.tv_sec = TIMEOUT;
        timeout.tv_nsec = 0;

        retval = recvmmsg(sockfd, msgs, VLEN, 0, &timeout);
        if (retval == -1) {
            perror("recvmmsg()");
            exit(EXIT_FAILURE);
        }

        printf("%d messages received\n", retval);
        for (size_t i = 0; i < retval; i++) {
            bufs[i][msgs[i].msg_len] = 0;
            printf("%zu %s", i+1, bufs[i]);
        }
        exit(EXIT_SUCCESS);
    }

انظر أيضًا
clock_gettime(2), recvmsg(2), sendmmsg(2), sendmsg(2), socket(2), socket(7)

ترجمة
تُرجمت هذه الصفحة من الدليل بواسطة زايد السعيدي <zayed.alsaidi@gmail.com>

هذه الترجمة هي وثيقة مجانية؛ راجع رخصة جنو العامة الإصدار 3 (https://www.gnu.org/licenses/gpl-3.0.html) أو ما بعده للاطلاع على شروط حقوق النشر. لا توجد أي ضمانات.

إذا وجدت أي أخطاء في ترجمة صفحة الدليل هذه، يرجى إرسال بريد إلكتروني إلى قائمة بريد المترجمين: kde-l10n-ar@kde.org.