System V
Message Queue based on System V
จะมีลักษณะคล้ายกับไฟล์ pipe คือสามารถส่งบล็อกข้อมูลจากโปรเซสหนึ่งไปยังอีกโปรเซสหนึ่งผ่านลีนุกซ์คอร์เนลเช่นเดียวกัน โดยแต่ละบล็อกข้อมูลจะมีหมายเลขอ้างอิงกำหนดไว้ให้เพื่อให้โปรเซสอื่นๆสามารถอ้างอิงหมายเลขข้อมูลที่ต้องการนั้นได้ ซึ่งจะไม่เหมือนกับการส่งข้อมูลผ่าน pipe ซึ่งทั้งสองโปรเซสจะต้องรอซึ่งกันและกัน ดังนั้นขั้นตอนการส่งข้อมูลแบบ message queue จะมีขั้นตอนคือโปรเซสที่ทำการเขียนข้อมูลไปยัง queue (ด้วยคำสั่ง msgsnd
) แล้ว ก็สามารถจบการทำงานได้ทันที ถ้าโปรเซสใดต้องการอ่านก็สามารถเข้าไปอ่านข้อมูลใน queue ได้ภายหลัง (ด้วยคำสั่ง msgrcv
) ซึ่งตัว message queue เปรียบเสมือนกล่องส่วนกลางที่จะมีโปรเซสใดก็ได้ที่สามารถเข้ามาทิ้งข้อมูลไว้ หรือจะมีโปรเซสใดก็ได้ที่จะเข้ามาดึงข้อความจากกล่องที่แชร์ไว้นี้ได้
ภายใต้มาตราฐาน System V IPC เมื่อโปรเซสมีการสร้าง message queue แล้ว แม้ว่าโปรเซสนั้นถูกทำลายหรือสิ้นสุดการทำงานไปแล้วก็ตาม แต่ตัว message queue นั้นก็ยังค้างอยู่ในระบบซึ่งสามารถใช้คำสั่ง ipcs ภายใน shell เพื่อแสดงรายการ message queue ที่มีอยู่ในระบบดังตัวอย่างการใช้งานข้างล่างและสามารถใช้คำสั่ง ipcrm
เมื่อต้องการลบ message queue ออกไปจากระบบ
$ ipcs -q
------ Message Queues --------
key msqid owner perms used-bytes messages
0x42016dfa 32768 sriborrirux 644 0 0
ตัวอย่างเช่น โปรแกรม A ต้องการสร้างกุญแจ เพื่อทำการสร้าง message queue ตัวใหม่ จะมีขั้นตอนดังนี้
...
key = ftok("/home/wiroon/somefile", 'P');
msqid = msgget(key, 0666 | IPC_CREAT);
...
ซึ่งจากคำสั่งข้างต้นก็จะได้ message queue ที่มีสิทธิ์การเข้าถึงเป็น 666
หรือ rw-rw-rw-
และหมายเลขเฉพาะของ msqid
เพื่อให้โปรเซสอื่นๆอ้างอิงหมายเลขของ message queue ที่ต้องการจะเข้าถึงได้ แต่อย่างไรก็ตามโปรเซสใดก็ตามถ้าต้องการเข้าถึง message queue ที่ถูกสร้างโดยโปรแกรม A ก็จะต้องมีขั้นตอนในการนำกุญแจที่จะสามารถเข้ามาเปิดเอาหมายเลข message queue นั้นได้ ดังนั้น โปรแกรมอื่นๆ จึงจำเป็นต้องใช้พารามิเตอร์ภายในฟังก์ชัน ftok()
เดียวกันโปรแกรม A ใช้ แล้วจึงจะได้หมายเงขของ message queue (msqid) โดยใช้คำสั่งภายในดังตัวอย่างโปรแกรมข้างล่างนี้
...
key = ftok("/home/wiroon/somefile", 'P');
msqid = msgget(key, 0666);
...
หลังจากสร้างกุญแจและ message queue ได้เรียบร้อยแล้ว แต่อย่างไรก็ตาม message queue ก็ยังมีข้อจำกัดเรื่องขนาดบล็อกข้อมูล ที่จะถูกจำกัดขนาดไว้รวมทั้งจำนวนบล็อกทั้งหมดที่มีบนระบบก็จะถูกจำกัดไว้เช่นกัน ซึ่งภายในระบบปฏิบัติการลีนุกซ์ตัวแปรบล็อกข้อมูลจะประกอบไปด้วย 2 ส่วนคือ MSGMAX(4096)
และ MSGMNB(16384)
ซึ่งตัวแรกจะหมายถึงความจุของแต่ละบล็อกข้อความ และตัวที่สองจะหมายถึงความจุทั้งหมดของ queue แต่ในบางระบบ ค่าเหล่านี้อาจจะแตกต่างกันไป หรืออาจจะไม่ใช้ค่านี้เลยก็เป็นได้
ในทางปฏิบัติการสร้างข้อมูลเพื่อนำไปเก็บไว้ใน message queue จะมีการสร้างให้อยู่ในลักษณะตัวแปรแบบ struct เช่น
struct my_msgbuf {
long mtype;
char mtext[200];
};
ซึ่งสังเกตว่าจะมีการกำหนดตัวแปร mtype ที่เป็นชนิด long ไว้เริ่มต้นเสมอ ตามคำแนะนำของการใช้งาน message queue ดังนั้นเมื่อต้องหาขนาดของข้อมูลที่แท้จริง จำเป็นจะต้องลบด้วยขนาดของตัวแปร mtype ก่อนเสมอ เช่น
/* calculate the size of the data to send: */
int size = sizeof(struct my_msgbuf) - sizeof(long);

แสดงตัวอย่างโปรแกรมสำหรับส่งบล๊อกข้อมูลเข้าไปใน Message Queues โดยสร้างโปรแกรมส่งข้อมูลไปเก็บไว้ใน message queue ชื่อว่า msg_sender.c
และโปรแกรมสำหรับอ่านค่าจาก message queue ชื่อว่า msg_receiver.c
ดังข้างล่างนี้
/*
* System V IPC
** msg_sender.c -- writes to a message queue
*/
#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("msg_sender.c", '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; /* in this case we don’t need to classify any data types yet */
while (fgets((buf.mtext), sizeof(buf) + 1, stdin)) {
if (msgsnd(msqid, (struct msgbuf*) &buf, sizeof(buf), 0) == -1)
perror("msgsnd");
}
if (msgctl(msqid, IPC_RMID, NULL) == -1) {
perror("msgctl");
exit(1);
}
return 0;
}
โปรแกรม msg_receiver.c
สำหรับอ่านบล๊อกข้อมูลภายใน Message Queues ที่โปรแกรม msg_sender.c
เขียนข้อมูลเข้าไป
/*
** msg_receiver.c -- reads from a message queue
*/
#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("msg_sender.c", 'B')) == -1) {
/* same key as msg_sender.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, (struct msgbuf*) &buf, sizeof(buf), 0, 0) == -1) {
perror("msgrcv");
exit(1);
}
printf("spock: \"%s\"\n", buf.mtext);
}
return 0;
}
ทำการคอมไพล์โปรแกรม msg_sender
แล้วรันโปรแกรมเพื่อพร้อมเขียนข้อมูลลง message queue ต่อไป
$ gcc -o msg_sender msg_sender.c -Wall
$ ./msg_sender
Enter lines of text, ^D to quit:
กลับมาที่ หน้าต่าง Terminal ที่ 1 เพื่อทำการพิมพ์ข้อความเพื่อส่งไปยัง msg_receiver ดังตังอย่างข่างล่าง
หน้าต่าง Terminal ที่ 1
...
Enter lines of text, ^D to quit:
Hello from Sender.... <-- ข้อความที่พิพม์จาก msg_sender ในหน้าต่าง terminal ที่ 1
จะสังเกตุเห็นข้อความปรากฏขึ้นในหน้าต่าง Terminal ที่ 2 เนื่องจากโปรเซส msg_receiver ได้รับแล้วแสดงดังนี้
หน้าต่าง Terminal ที่ 2
...
spock: ready to receive messages, captain.
spock: "Hello from Sender...." <-- ข้อความที่ msg_receiver ได้รับ ในหน้าต่าง terminal ที่ 2
Last updated
Was this helpful?