MSGOP(2)

الاسم
msgrcv, msgsnd - عمليات طابور رسائل System V

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

موجز
#include <sys/msg.h>

ssize_t msgrcv(size_t msgsz;
               int msqid, void msgp[msgsz], size_t msgsz, long msgtyp,
               int msgflg);

int msgsnd(size_t msgsz;
               int msqid, const void msgp[msgsz], size_t msgsz,
               int msgflg);

الوصف
استدعاءات النظام msgsnd() و msgrcv() تُستخدم لإرسال الرسائل إلى طابور رسائل System V واستقبالها منه. يجب أن تمتلك العملية المستدعية صلاحية الكتابة على طابور الرسائل لإرسال رسالة، وصلاحية القراءة لاستقبال رسالة.

الوسيط msgp هو مؤشر إلى بنية معرفة من قبل المستدعي بالشكل العام التالي:

    struct msgbuf {
        long mtype;       /* نوع الرسالة، يجب أن يكون > 0 */
        char mtext[1];    /* بيانات الرسالة */
    };

الحقل mtext هو مصفوفة (أو بنية أخرى) يُحدد حجمها بواسطة msgsz، وهي قيمة عددية غير سالبة. يُسمح برسائل ذات طول صفري (أي لا يوجد حقل mtext). يجب أن يحتوي الحقل mtype على قيمة عددية موجبة تمامًا. يمكن استخدام هذه القيمة من قبل العملية المستقبلة لاختيار الرسالة (انظر وصف msgrcv() أدناه).

  msgsnd()
استدعاء النظام msgsnd() يُلحق نسخة من الرسالة المشار إليها بواسطة msgp إلى طابور الرسائل الذي يُحدد معرفه بواسطة msqid.

إذا توفرت مساحة كافية في الطابور، ينجح msgsnd() فورًا. سعة الطابور تُحكم بواسطة الحقل msg_qbytes في بنية البيانات المرتبطة بطابور الرسائل. أثناء إنشاء الطابور، يُهيأ هذا الحقل إلى MSGMNB بايت، لكن يمكن تعديل هذا الحد باستخدام msgctl(2). يُعتبر طابور الرسائل ممتلئًا إذا تحقق أحد الشرطين التاليين:

•   إضافة رسالة جديدة إلى الطابور ستؤدي إلى تجاوز العدد الإجمالي للبايتات في الطابور للحجم الأقصى للطابور (الحقل msg_qbytes).

•   إضافة رسالة أخرى إلى الطابور ستؤدي إلى تجاوز العدد الإجمالي للرسائل في الطابور للحجم الأقصى للطابور (الحقل msg_qbytes). هذا الفحص ضروري لمنع وضع عدد غير محدود من الرسائل ذات الطول الصفري في الطابور. على الرغم من أن هذه الرسائل لا تحتوي على بيانات، إلا أنها تستهلك ذاكرة نواة (مقفلة).

إذا لم تتوفر مساحة كافية في الطابور، فإن السلوك المبدئي لـ msgsnd() هو الحظر حتى تتوفر مساحة. إذا تم تحديد IPC_NOWAIT في msgflg، فإن الاستدعاء يفشل بدلاً من ذلك مع الخطأ EAGAIN.

قد يفشل استدعاء msgsnd() المحظور أيضًا إذا:

•   تمت إزالة الطابور، وفي هذه الحالة يفشل استدعاء النظام مع تعيين errno إلى EIDRM؛ أو

•   تم التقاط إشارة، وفي هذه الحالة يفشل استدعاء النظام مع تعيين errno إلى EINTR؛ انظر signal(7). (لا يُعاد تشغيل msgsnd() آليًا بعد مقاطعته بواسطة معالج إشارة، بغض النظر عن إعداد العلم SA_RESTART عند إنشاء معالج الإشارة.)

عند الإكمال بنجاح، تُحدث بنية بيانات طابور الرسائل كما يلي:

•   msg_lspid يُضبط إلى معرف العملية للعملية المستدعية.

•   msg_qnum يُزاد بمقدار 1.

•   msg_stime يُضبط إلى الوقت الحالي.

  msgrcv()
استدعاء النظام msgrcv() يزيل رسالة من الطابور المحدد بواسطة msqid ويضعها في المخزن المؤقت المشار إليه بواسطة msgp.

الوسيط msgsz يُحدد الحجم الأقصى بالبايتات للعضو mtext من البنية المشار إليها بواسطة الوسيط msgp. إذا كان طول نص الرسالة أكبر من msgsz، فإن السلوك يعتمد على ما إذا كان MSG_NOERROR محددًا في msgflg. إذا تم تحديد MSG_NOERROR، فسيُقتطع نص الرسالة (وسيُفقد الجزء المقتطع)؛ إذا لم يُحدد MSG_NOERROR، فلن تُزال الرسالة من الطابور ويفشل استدعاء النظام بإرجاع -1 مع تعيين errno إلى E2BIG.

ما لم يُحدد MSG_COPY في msgflg (انظر أدناه)، فإن الوسيط msgtyp يُحدد نوع الرسالة المطلوبة، كما يلي:

•   إذا كان msgtyp يساوي 0، فتُقرأ أول رسالة في الطابور.

•   إذا كان msgtyp أكبر من 0، فتُقرأ أول رسالة في الطابور من النوع msgtyp، ما لم يُحدد MSG_EXCEPT في msgflg، وفي هذه الحالة تُقرأ أول رسالة في الطابور من نوع لا يساوي msgtyp.

•   إذا كان msgtyp أقل من 0، فتُقرأ أول رسالة في الطابور ذات النوع الأدنى الأصغر من أو المساوي للقيمة المطلقة لـ msgtyp.

الوسيط msgflg هو قناع بتات يُبنى بواسطة OR معًا صفرًا أو أكثر من الأعلام التالية:

IPC_NOWAIT
    أرجع فورًا إذا لم تكن هناك رسالة من النوع المطلوب في الطابور. يفشل استدعاء النظام مع تعيين errno إلى ENOMSG.

MSG_COPY (منذ لينكس 3.8)
    اجلب نسخة غير مدمرة من الرسالة في الموضع الترتيبي في الطابور المحدد بواسطة msgtyp (تُعتبر الرسائل مرقمة بدءًا من 0).

    يجب تحديد هذه العلامة بالتزامن مع IPC_NOWAIT، مما يؤدي إلى أنه إذا لم تكن هناك رسالة متاحة في الموضع المحدد، يفشل الاستدعاء فورًا مع الخطأ ENOMSG. نظرًا لأنهما يغيران معنى msgtyp بطرق متعامدة، لا يمكن تحديد كل من MSG_COPY وMSG_EXCEPT في msgflg.

    أُضيفت العلامة MSG_COPY لتنفيذ مرفق استعادة نقطة التفتيش للنواة وهي متاحة فقط إذا بُنيت النواة مع الخيار CONFIG_CHECKPOINT_RESTORE.

MSG_EXCEPT
    تُستخدم مع msgtyp أكبر من 0 لقراءة أول رسالة في الطابور بنوع رسالة يختلف عن msgtyp.

MSG_NOERROR
    لاقتطاع نص الرسالة إذا كان أطول من msgsz بايت.

إذا لم تكن هناك رسالة من النوع المطلوب متاحة ولم يُحدد IPC_NOWAIT في msgflg، فتُحجب العملية المستدعية حتى يحدث أحد الشروط التالية:

•   تُوضع رسالة من النوع المطلوب في الطابور.

•   تُزال طابور الرسائل من النظام. في هذه الحالة، يفشل استدعاء النظام مع تعيين errno إلى EIDRM.

•   تلتقط العملية المستدعية إشارة. في هذه الحالة، يفشل استدعاء النظام مع تعيين errno إلى EINTR. (لا يُعاد تشغيل msgrcv() آليًا بعد مقاطعته بواسطة معالج إشارة، بغض النظر عن إعداد العلامة SA_RESTART عند إنشاء معالج إشارة.)

عند الإكمال بنجاح، تُحدث بنية بيانات طابور الرسائل كما يلي:

    يُعيّن msg_lrpid إلى معرف العملية للعملية المستدعية.

    يُقلّص msg_qnum بمقدار 1.

    يُعيّن msg_rtime إلى الوقت الحالي.

قيمة الإرجاع
عند النجاح، تُرجع msgsnd() 0 وتُرجع msgrcv() عدد البايتات المنسوخة فعليًا في مصفوفة mtext. عند الفشل، تُرجع كلتا الدالتين -1، وتُعيّنان errno للإشارة إلى الخطأ.

الأخطاء
يمكن أن تفشل msgsnd() مع الأخطاء التالية:

EACCES
    لا تملك العملية المستدعية إذن الكتابة على طابور الرسائل، ولا تملك القدرة CAP_IPC_OWNER في مساحة اسم المستخدم التي تحكم مساحة اسم IPC الخاصة بها.

EAGAIN
    لا يمكن إرسال الرسالة بسبب حد msg_qbytes للطابور وتم تحديد IPC_NOWAIT في msgflg.

EFAULT
    العنوان المشار إليه بواسطة msgp غير قابل للوصول.

EIDRM
    حُذف طابور الرسائل.

EINTR
    أثناء النوم على حالة طابور رسائل ممتلئ، التقطت العملية إشارة.

EINVAL
    قيمة msqid غير صالحة، أو قيمة mtype غير موجبة، أو قيمة msgsz غير صالحة (أقل من 0 أو أكبر من قيمة النظام MSGMAX).

ENOMEM
    لا يملك النظام ذاكرة كافية لعمل نسخة من الرسالة المشار إليها بواسطة msgp.

يمكن أن تفشل msgrcv() مع الأخطاء التالية:

E2BIG
    طول نص الرسالة أكبر من msgsz ولم يُحدد MSG_NOERROR في msgflg.

EACCES
    لا تملك العملية المستدعية إذن القراءة على طابور الرسائل، ولا تملك القدرة CAP_IPC_OWNER في مساحة اسم المستخدم التي تحكم مساحة اسم IPC الخاصة بها.

EFAULT
    العنوان المشار إليه بواسطة msgp غير قابل للوصول.

EIDRM
    بينما كانت العملية نائمة لاستقبال رسالة، أُزيل طابور الرسائل.

EINTR
    بينما كانت العملية نائمة لاستقبال رسالة، التقطت العملية إشارة؛ انظر signal(7).

EINVAL
    كان msqid غير صالح، أو كان msgsz أقل من 0.

EINVAL (منذ لينكس 3.14)
    msgflg حدد MSG_COPY، ولكن ليس IPC_NOWAIT.

EINVAL (منذ لينكس 3.14)
    msgflg حدد كلاً من MSG_COPY و MSG_EXCEPT.

ENOMSG
    IPC_NOWAIT تم تحديده في msgflg ولم توجد رسالة من النوع المطلوب في طابور الرسائل.

ENOMSG
    IPC_NOWAIT و MSG_COPY تم تحديدهما في msgflg ويحتوي الطابور على أقل من msgtyp رسالة.

ENOSYS (منذ لينكس 3.8)
    كلا من MSG_COPY و IPC_NOWAIT تم تحديدهما في msgflg، وتم تكوين هذه النواة بدون CONFIG_CHECKPOINT_RESTORE.

المعايير
POSIX.1-2024 XSI.

العلمان MSG_EXCEPT و MSG_COPY خاصان بلينكس؛ يمكن الحصول على تعريفاتهما بتعريف ماكرو اختبار الميزة _GNU_SOURCE.

التاريخ
SVr4, SUSv1, POSIX.1-2001 XSI.

الوسيطة msgp مُعلنة كـ struct msgbuf * في glibc 2.0 و 2.1. وهي مُعلنة كـ void * في glibc 2.2 وما بعده، كما هو مطلوب بواسطة SUSv2 و SUSv3.

ملاحظات
الحدود التالية على موارد طابور الرسائل تؤثر على استدعاء msgsnd():

MSGMAX
    الحد الأقصى لحجم نص الرسالة، بالبايت (القيمة المبدئية: 8192 بايت). في لينكس، يمكن قراءة هذا الحد وتعديله عبر /proc/sys/kernel/msgmax.

MSGMNB
    الحد الأقصى لعدد البايتات التي يمكن الاحتفاظ بها في طابور رسائل (القيمة المبدئية: 16384 بايت). في لينكس، يمكن قراءة هذا الحد وتعديله عبر /proc/sys/kernel/msgmnb. يمكن لعملية متميزة (لينكس: عملية مع إمكانية CAP_SYS_RESOURCE) زيادة حجم طابور الرسائل بما يتجاوز MSGMNB باستخدام عملية msgctl(2) IPC_SET.

التنفيذ ليس له حدود نظامية جوهرية على عدد رؤوس الرسائل (MSGTQL) وعدد البايتات في مجمع الرسائل (MSGPOOL).

العلل
في لينكس 3.13 وما قبله، إذا تم استدعاء msgrcv() مع العلم MSG_COPY، ولكن بدون IPC_NOWAIT، واحتوى طابور الرسائل على أقل من msgtyp رسالة، فإن الاستدعاء سينتظر حتى تتم كتابة الرسالة التالية في الطابور. عند تلك النقطة، سيعيد الاستدعاء نسخة من الرسالة، بغض النظر عما إذا كانت تلك الرسالة في الموضع الترتيبي msgtyp. تم إصلاح هذا الخلل في لينكس 3.14.

تحديد كلا من MSG_COPY و MSC_EXCEPT في msgflg هو خطأ منطقي (حيث أن هذه الأعلام تفرض تفسيرات مختلفة على msgtyp). في لينكس 3.13 وما قبله، لم يتم تشخيص هذا الخطأ بواسطة msgrcv(). تم إصلاح هذا الخلل في لينكس 3.14.

أمثلة
البرنامج أدناه يوضح استخدام msgsnd() و msgrcv().

يتم تشغيل البرنامج المثال أولاً مع الخيار -s لإرسال رسالة ثم تشغيله مرة أخرى مع الخيار -r لاستقبال رسالة.

تظهر جلسة الصدفة التالية تشغيلًا نموذجيًا للبرنامج:

    $ ./a.out -s
    sent: a message at Wed Mar  4 16:25:45 2015

$ ./a.out -r
message received: a message at Wed Mar  4 16:25:45 2015

  مصدر البرنامج
    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    #include <time.h>
    #include <unistd.h>

    struct msgbuf {
        long mtype;
        char mtext[80];
    };

    static void
    usage(char *prog_name, char *msg)
    {
        if (msg != NULL)
            fputs(msg, stderr);

        fprintf(stderr, "Usage: %s [options]\n", prog_name);
        fprintf(stderr, "Options are:\n");
        fprintf(stderr, "-s        send message using msgsnd()\n");
        fprintf(stderr, "-r        read message using msgrcv()\n");
        fprintf(stderr, "-t        message type (default is 1)\n");
        fprintf(stderr, "-k        message queue key (default is 1234)\n");
        exit(EXIT_FAILURE);
    }

    static void
    send_msg(int qid, int msgtype)
    {
        time_t         t;
        struct msgbuf  msg;

        msg.mtype = msgtype;

        time(&t);
        snprintf(msg.mtext, sizeof(msg.mtext), "a message at %s",
                 ctime(&t));

        if (msgsnd(qid, &msg, sizeof(msg.mtext),
                   IPC_NOWAIT) == -1)
        {
            perror("msgsnd error");
            exit(EXIT_FAILURE);
        }
        printf("sent: %s\n", msg.mtext);
    }

    static void
    get_msg(int qid, int msgtype)
    {
        struct msgbuf msg;

        if (msgrcv(qid, &msg, sizeof(msg.mtext), msgtype,
                   MSG_NOERROR | IPC_NOWAIT) == -1) {
            if (errno != ENOMSG) {
                perror("msgrcv");
                exit(EXIT_FAILURE);
            }
            printf("No message available for msgrcv()\n");
        } else {
            printf("message received: %s\n", msg.mtext);
        }
    }

    int
    main(int argc, char *argv[])
    {
        int  qid, opt;
        int  mode = 0;               /* 1 = send, 2 = receive */
        int  msgtype = 1;
        int  msgkey = 1234;

        while ((opt = getopt(argc, argv, "srt:k:")) != -1) {
            switch (opt) {
            case 's':
                mode = 1;
                break;
            case 'r':
                mode = 2;
                break;
            case 't':
                msgtype = atoi(optarg);
                if (msgtype <= 0)
                    usage(argv[0], "-t option must be greater than 0\n");
                break;
            case 'k':
                msgkey = atoi(optarg);
                break;
            default:
                usage(argv[0], "Unrecognized option\n");
            }
        }

        if (mode == 0)
            usage(argv[0], "must use either -s or -r option\n");

        qid = msgget(msgkey, IPC_CREAT | 0666);

        if (qid == -1) {
            perror("msgget");
            exit(EXIT_FAILURE);
        }

        if (mode == 2)
            get_msg(qid, msgtype);
        else
            send_msg(qid, msgtype);

        exit(EXIT_SUCCESS);
    }

انظر أيضًا
msgctl(2), msgget(2), capabilities(7), mq_overview(7), sysvipc(7)

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

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

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