Message Queue C on Unix/Linux
วันนี้อยู่บ้านวันอาทิตย์ว่าง ๆ ไม่ได้ทำอะไร ก็เลยมานั่งหาอะไรอ่าน เอาความรู้ใส่สมอง ซักหน่อย
ก็เลยมาอ่านเกี่ยวกับเรื่อง Message Queue และก็ลองเขียนเล่นๆ ดู ก็ผมจะสรุปตามความเข้าใจของผม และย่อตัวอย่าง Code ที่ใช้งานดูนะครับ
Message Q คืออะไร และใช้ทำอะไร ?
ก่อนที่จะมาทำความรู้จักกับ Message Queue เรามาทำความรู้จักกับ IPC กันก่อน IPC หรือ Interprocess Communication มีไว้เพื่อการติดต่อสื่อสาร จะใช้ในการติดต่อสื่อสารระหว่าง Thread ภายใน Process เดียวกันก็ได้ หรือ จะใช้ในการติดต่อสารระหว่าง Process ก็ได้
โดยการสื่อสารของ IPC มีหลายชนิด และแต่ละชนิดมีข้อดีข้อเสียแตกต่างกันไปครับ
- Pipes
- Signal
- Message Queue
- Shared Memory
- Socket
- Semaphores
Page จะพูดเรื่อง Message Queue ก่อนนะครับ แล้วผมจะค่อย ๆ เพิ่มในส่วนอื่นให้ภายหลัง Message Queue สามารถติดต่อสื่อสารกันภายใน OS เดียวกันได้เท่านั้น คือ ตัว Message Queue ไม่สามารถสื่อสารข้ามเครื่องได้ ต้องอยู่ภายใต้เครื่องเดียวกันเท่านั้น
โดยการทำงานคร่าวๆ ของ Message Queue นั้นแน่นอนว่าจะมีในส่วนของการส่งและการรับ และที่เพิ่มเข้ามาจะเป็นในส่วนของ Passing Module ซึ่งทำหน้าที่เป็นตัวกลางในการจัดการ รับ-ส่ง Message ให้กับทั้ง 2 Process และ ใน Process ทั้งสองจะต้องกำหนดค่า Key ขึ้น ให้ตรงกัน เช่น Process ที่ส่ง ส่งด้วย Key 1234 ใน Process ในการรับก็ต้องรับ ด้วย Key 1234 ด้วย
ในใช้งาน Function หรือ type ต่าง ๆ ของ Message Queue จะต้อง include header file 3 file ดังนี้
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
function หลักๆ ของ Message ที่ใช้มีดังนี้ msgget(), msgsnd(), msgrcv()
- int msgget(key_t key, int msgflg)
- int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
- int msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
1. msgget ใช้ในการสร้างช่องทางในการรับ-ส่ง
- return ค่าของ Messsage Queue ID มาให้หาก function นี้ทำงานสำเร็จ และ return -1 หาก error
- key คือเลขคือ ซื่งตัวแปล key จะมีขนาด เทียบเท่า unsigned long
- msgflg คือ parameter ที่ใช้ตั้งค่า permission และ control flag ของ message queue
2. msgsnd ใช้ในการส่ง
- return หาก function นี้ทำงานไม่สำเร็จจะ return -1
- msqid คือ message queue id ที่ได้จากการ call function msgget
- msgp คือ structure ของ message ที่ จะส่งออกไป
- msgsz คือ ขนาดของ structure ของ message ที่จะส่งออก
- msgflg คือ flag เพื่อบอกว่า call function นี้แล้วให้ทำอะไร ส่วนใหญ่ที่ผมใช้คือ IPC_NOWAIT
3.msgrcv ใช้ในการรับ
- return หาก function นี้ทำงานสำเร็จจะ return ขนาดของ Message ที่รับเข้ามา แต่หากไม่สำเร็จจะ return -1
- msqid คือ Qessage Queue id ที่ได้จากการ call function msgget
- msgp คือ structure ของ message ที่ จะรับเข้ามา
- msgsz คือ ขนาดของ structure ของ message ที่จะรับเข้ามา
- msgtyp คือ จะรับ Message type อะไร
- msgflg คือ flag เพื่อบอกว่า call function นี้แล้วให้ทำอะไร
Code Example
โดยตัวอย่างผมจะแบ่งออกเป็น 2 Process (2 โปรแกรม)
- โปรแกรมส่ง Send Process
- โปรแกรมรับ Receive Process
1.msgq_send.c
/*************************
*@author Ultra MCU
*@file-name msgq_send.c
*@date 2011 02 13
*compile apple-darwin10-gcc-4.2.1 on OSX 10.6.4
*@e-mail ultra_mcu[AT]msn>com
*@website http://www.im-ai.com
*************************/#include
#include
#include
#include#define _TRUE_ 0
#define _FALSE_ -1typedef struct struct_message_text
{
long message_type;
char message_text[100];}st_msg_txt;
int main (int argc, const char * argv[]) {
printf(“Hello, I’m send process.\r\n”);
send_process();
return 0;
}int send_process()
{
st_msg_txt my_send_msg;
key_t msg_key;
int msg_flag;
int msg_q_id;
int msg_number;msg_number = 0;
msg_key = 822; /* Message Queue Key 822 */
msg_flag = IPC_CREAT | 0666; /* IPC Create + Permission rw_rw_rw_ */
my_send_msg.message_type = 1; /* Message type 1 */
msg_q_id = msgget(msg_key, msg_flag);if(msg_q_id > -1)
{
while(1)
{
sprintf(my_send_msg.message_text,”Message msg_number = %d”,msg_number);if(msgsnd(msg_q_id, &my_send_msg, sizeof(st_msg_txt), IPC_NOWAIT) == _TRUE_)
{
printf(“SEND PROCESS : %s\r\n”,my_send_msg.message_text);
}
else
{
perror(“msgsnd”);
printf(“send message failed\r\n”);
return _FALSE_;
}msg_number++;
sleep(1);
}
}
else
{
printf(“get message queue id failed\r\n”);
return _FALSE_;
}return _TRUE_;
}
2.msgq_recv.c
/*************************
*@author Ultra MCU
*@file-name msgq_recv.c
*@date 2011 02 13
*compile apple-darwin10-gcc-4.2.1 on OSX 10.6.4
*@e-mail ultra_mcu[AT]msn>com
*@website http://www.im-ai.com
*************************/#include
#include
#include
#include#define _TRUE_ 0
#define _FALSE_ -1typedef struct struct_message_text
{
long message_type;
char message_text[100];}st_msg_txt;
int main (int argc, const char * argv[]) {
printf(“Hello, I’m recv process.\r\n”);
recv_process();
return 0;
}
int recv_process()
{
st_msg_txt my_recv_msg;
key_t msg_key;
int msg_flag;
int msg_q_id;
int recv_msg_type;msg_key = 822; /* Message Queue Key 822 */
msg_flag = IPC_CREAT | 0666; /* IPC Create + Permission rw_rw_rw_ */
recv_msg_type = 1; /* Receive Message type 1 */msg_q_id = msgget(msg_key, msg_flag);
if(msg_q_id > -1)
{
while(1)
{
if(msgrcv(msg_q_id, &my_recv_msg, sizeof(st_msg_txt),recv_msg_type , 0) < 0)
{
perror(“msgrcv”);
printf(“recv message failed\r\n”);
return _FALSE_;
}
else
{
printf(“RECV PROCESS : %s\r\n”,my_recv_msg.message_text);
}
}
}
else
{
printf(“get message queue id failed\r\n”);
return _FALSE_;
}return _TRUE_;
}
ดังไฟล์ source code ตัวอย่างเป็นการรับส่ง message queue ด้วย key 822 และใช้ message type เป็น 1 โดย ทุกๆ 1 วินาที Process ที่ส่งจะส่งข้อความ “Message msg_number =XXX” ไปหา Process รับโดยเลข XXX จะนับเพิ่มขึ้นเรื่อย ๆ
จากตัวอย่าง หน้าจอสีแดงคือ Process รับ ส่วนหน้าจอสีขาวคือ Process ส่ง
นี่ก็เป็นตัวอย่างง่าย ๆ ของการสร้างการสื่อสารภายใน Application หรือระหว่าง Application ได้ง่ายและรวดเร็ว เพียงแค่เขียน code เพิ่มไม่กี่บรรทัด ซึ่งข้อดีของการใช้ Message Queue คือพัฒนาได้เร็ว รับส่งเร็ว แต่ข้อเสียคือขนาดของการส่งมีจำกัด ดูได้จากคำสั่ง ulimit -q แต่สามารถเปลี่ยนแปลงได้ ตามคำสั่งของ Unix นั้นๆ ครับ
ปล.หากต้องการนำไปเผยแพร่ ขอความกรุณาใส่เครดิต ให้ด้วยครับ ขอบคุณครับ
Ref : http://www.cs.cf.ac.uk/Dave/C/node25.html
Ref : http://linux.die.net/man/3/msgget

