נציג דוגמא ל-msg queues. כמו בהרבה פונקציות מערכת, גם כאן קיימם שני סוגי מימוש לmsg queues. מימוש של posix ומימוש של system v . המימושים הנ"ל די דומים. הדוגמא שנראה כאן משתמשת ב- system v api.
הדוגמא כוללת שני קבצים: kirk.c, האחראי על שליחת הודעות ל-msg queue - התוכנית קולטת את ההודעת אינטראקטיבית מהמשתמש שמקליד אותן, ו-spoke.c האחראי על שליפת ההודעות מה-msg queue ושליחתן לתצוגה.
הדוגמא לקוחה כולה מתוך Beej's Guide to Unix IPC.
נתחיל עם הקובץ kirk.c
בקובץ שלוש פונקציות עיקריות - מודגשות בצהוב.
1. יצירת ה-msg queueu
2. שליחת הודעות ל-msg queueu
3. מחיקת ה-queue
- *
- * kirk.c
- *
- * Created on: May 10, 2012
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
- struct my_msgbuf {
- long mtype;
- char mtext[200];
- };
- int main(void)
- {
- struct my_msgbuf buf;
- int msqid;
- key_t key;
- if ((key = ftok("/tmp", 'B')) == -1) {
- perror("ftok");
- exit(1);
- }
- if ((msqid = msgget(key, 0644 | IPC_CREAT)) == -1) {
- perror("msgget");
- exit(1);
- }
- printf("Enter lines of text, ^D to quit:\n");
- buf.mtype = 1; /* we don't really care in this case */
- while(fgets(buf.mtext, sizeof buf.mtext, stdin) != NULL) {
- int len = strlen(buf.mtext);
- struct my_msgbuf {
- long mtype;
- char mtext[200];
- };
- /* ditch newline at end, if it exists */
- if (buf.mtext[len-1] == '\n') buf.mtext[len-1] = '\0';
- if (msgsnd(msqid, &buf, len+1, 0) == -1) /* +1 for '\0' */
- perror("msgsnd");
- }
- if (msgctl(msqid, IPC_RMID, NULL) == -1) {
- perror("msgctl");
- exit(1);
- }
- return 0;
- }
הפונקציה main מבצעת שליחה של הודעות ל-msg queue.
ההודעות מוקלדות ע"י המשתמש ונקלטות ע"י fgets - ראו שורות 43-47.
main מפעילה 3 פונקציות הקשורות ל=msg queue (מודגשות בצהוב):
שורה 34 - msgget, יוצרת את ה-queue.
שורה 49 - msgsnd שולחת הודעה ל-queue.
שורה 53 - מחיקת ה-queue בסיום.
נתחיל עם יצירת ה-queue - שורה 34:
msgget
הנה ה-prototype של msgget:
int msgget(key_t key, int msgflg);
if (msgrcv(msqid, &buf, sizeof(buf.mtext), 0, 0) == -1) {
הפונקציה מקבלת שני פרמטרים:
key - זהו למעשה משתנה מסוג long, שמהווה מציין עבור ה-queue. כדי לגשת ל-queue הזה מכל process שהוא, יש להשתמש באותו מציין. אין שני msg queues עם אותו key.
msgflag - ה-flag הוא למעשה שילוב של flag ושל ה-permission עבור ה-queue.
בדוגמא שלנו למשל, בשורה 34:
if ((msqid = msgget(key, 0644 | IPC_CREAT)) == -1) {
msgflag הוא OR של 644 (rw-r-r) ושל IPC_CREAT שמסמן לצור msg queue חדש. נראה מאוחר יותר שבפעולת ה-msgget בצד הקולט, הדגל IPC_CREAT לא קיים.
לגבי בחירת ה-key - את ה-key אפשר לקבוע באופן חופשי. ומה אם ה-key שבחרנו כבר תפוס? זו אכן בעיה. נשתמש בפונקציה ftok שמייצרת key עפ"י שם קובץ כלשהו (שצריך להיות קיים על הדיסק). ftok אמורה לעזור בבחירת unique key.
ראו שורה 29:
(key = ftok("/tmp", 'B'))
הנה ה-prototype של ftok:
key_t ftok(const char *path, int id);
(key = ftok("/tmp", 'B'))
הנה ה-prototype של ftok:
key_t ftok(const char *path, int id);
msgsnd
שורה 49 - כאן מתבצעת השליחה ל-queue.
msgsnd
שורה 49 - כאן מתבצעת השליחה ל-queue.
הנה ה-prototype של msgsnd:
פרוט 4 הפרמטרים של הפונקציה:
msgqid - הערך המוחזר ע"י msgget.
msgp - מצביע על ה-buffer של ה--data שתשלח ל-queue. הסבר על מבנה ה-buffer מיד.
msgsz - כמות ה-bytes שישלחו ל-queue. גודל ה-buffer לא כולל את ה-mtype - הסבר על מבנה ה-buffer מיד בהמשך.
msgsz - כמות ה-bytes שישלחו ל-queue. גודל ה-buffer לא כולל את ה-mtype - הסבר על מבנה ה-buffer מיד בהמשך.
msgflg - דגלים לאפיונים שונים. כרגע נשים 0.
מבנה ה-buffer הנמסר ל-msg queue
הפרמטר השני בפונקציה msgsnd מצביע על ה-buffer שישלח ל-queue.
ה-buffer בדוגמא הנ"ל נראה כך - שורות 18-21:
struct my_msgbuf {
long mtype;
char mtext[200];
};
long mtype;
char mtext[200];
};
בראש ה-buffer נמצא משתנה ה-mtype מסוג long. הוא תמיד חייב להיות כאן.
אחריו - המקום לשמירת הנתונים עצמם. הם כמובן לא חייבים להיות char, כך שגם הדוגמא הבאה תקינה:
struct my_msgbuf {
long mtype;
int mtext[10];
};
ערכו של ה-mtype יכול לשמש לקביעת סדר שליפת הנתונים מה-buffer ע"י הצד הקולט. נראה זאת כשנדון ב-msgrcv.
גודל ה-buffer - הפרמטר השלישי ב-msgsnd, אינו כולל את שדה ה-msgtype, כך שבדוגמא שלנו, הגודל יהיה שווה לגודל המערך mtext, כלומר 200.
msgcntl
מחיקת ה-queue.
שורה 53:
if (msgctl(msqid, IPC_RMID, NULL) == -1) {
ה-prototype של msgctl:
שלושת הפרמטרים:
msgqid - הערך שמחזירה msgget.
cmd - הפעולה לביצוע/
struct msgqid_ds - מקבל כאן NULL.
נעבור לקובץ שממש את פונקצית הקריאה מה-msg queue:
- /*
- * spock.c
- *
- * Created on: May 10, 2012
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
- struct my_msgbuf {
- long mtype;
- char mtext[200];
- };
- int main(void)
- {
- struct my_msgbuf buf;
- int msqid;
- key_t key;
- if ((key = ftok("/tmp", 'B')) == -1) { /* same key as kirk.c */
- perror("ftok");
- exit(1);
- }
- if ((msqid = msgget(key, 0644)) == -1) { /* connect to the queue */
- perror("msgget");
- exit(1);
- }
- printf("spock: ready to receive messages, captain.\n");
- for(;;) { /* Spock never quits! */
- if (msgrcv(msqid, &buf, sizeof(buf.mtext), 0, 0) == -1) {
- perror("msgrcv");
- exit(1);
- }
- printf("spock: \"%s\"\n", buf.mtext);
- }
- return 0;
- }
כאן מדובר בשתי פונקציות המטפלות ב-nsg queue - מודגשות בצהוב:
שורה 31: msgget. מחזירה את ה-msgqid שישמש לכל הגישות ל-queue. הקריאה ל-msgget דומה לזו שראינו בקובץ kirk.c, רק שכאן הדגל IPC_CREAT לא קיים, היות שה-msg queue כבר נוצר.
ה-key חייב כמובן להיות זהה, ולכן הוא מיוצר כמו ב-kirk.c עם ftok - שורה 26/
שורה 39: קריאה מה-msg queue.
ה-prototype:
int msgrcv(int msqid, void *msgp, size_t msgsz,long msgtyp, int msgflg);
פרוט 5 הפרמטרים של הפונקציה:
msgqid - הערך המוחזר ע"י msgget.
msgp - מצביע על ה-data שתשלח ל-queue.
msgsz - כמות ה-bytes שישלחו ל-queue.
msgtyp - שלושת תחומי הערכים של msgtyp:
msgtyp<0: תשלף ההודעה הראשונה שה-mtype שלה קטן או שווה מערכו המוחלט של msgtyp.
msgtyp>0: תשלף ההודעה הראשונה שה-mtype שלה שווה ל msgtyp.
msgtyp=0: תשלף ההודעה הראשונה, בלי קשר לערכו של mtype.
--סוף--
אין תגובות:
הוסף רשומת תגובה