歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux 進程間通信(system v 消息隊列, 阻塞式)實例

Linux 進程間通信(system v 消息隊列, 阻塞式)實例

日期:2017/2/28 16:05:19   编辑:Linux教程

消息隊列(也叫做報文隊列)能夠克服早期unix通信機制的一些缺點。作為早期unix通信機制之一的信號能夠傳送的信息量有限,後來雖然POSIX 1003.1b在信號的實時性方面作了拓廣,使得信號在傳遞信息量方面有了相當程度的改進,但是信號這種通信方式更像"即時"的通信方式,它要求接受信號的進程在某個時間范圍內對信號做出反應,因此該信號最多在接受信號進程的生命周期內才有意義,信號所傳遞的信息是接近於隨進程持續的概念(process-persistent);管道及有名管道及有名管道則是典型的隨進程持續IPC,並且,只能傳送無格式的字節流無疑會給應用程序開發帶來不便,另外,它的緩沖區大小也受到限制。

/*
*
* Filename: producer.c
*
* Description: 生產者進程
*
* Version: 1.0
* Created: 09/30/2011 04:52:23 PM
* Revision: none
* Compiler: gcc(g++)
*
* Author: |Zhenghe Zhang|, |[email protected]|
* Company: |Shenzhen XXX Technology Co., Ltd.|
*
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <error.h>

#define BUFFER 10 //定義buf大小

struct msgtype {
long mtype;
char buf1[BUFFER + 1];
char buf2[BUFFER + 1];
long size;
};

int main()
{
key_t msgkey;

/*消息隊列*/
int msgid;
struct msgtype msg;

msgkey = ftok("/home/zhang/shmipcx", 10001);
if(msgkey == -1)
{
perror("ftok");
exit(1);
}

/*得到消息隊列標識符或創建一個消息隊列對象並返回消息隊列標識符*/
msgid = msgget(msgkey, IPC_CREAT | 0666);
if(msgid == -1)
{
perror("msgget");
exit(1);
}

int i = 0;
while(i < 10)
{
memset(msg.buf1, 0, BUFFER + 1);
memset(msg.buf2, 0, BUFFER + 1);

sprintf(msg.buf1, "buf1_0x%x", i);
sprintf(msg.buf2, "buf2_0x%x", i + 'a');

msg.mtype = 1001;
msg.size = i;

printf("msg.mtype = %ld, msg.size = %ld\t", msg.mtype, msg.size);
printf("msg.buf1 = %s, msg.buf2 = %s\n", msg.buf1, msg.buf2);

/*將msgp消息寫入到標識符為msqid的消息隊列*/
/*msgsz, 要發送消息的大小,不含消息類型占用的4個字節,即mtext的長度*/
/*msgflg 0:當消息隊列滿時,msgsnd將會阻塞,直到消息能寫進消息隊列*/
/*msgflg IPC_NOWAIT:當消息隊列已滿的時候,msgsnd函數不等待立即返回*/
/*msgflg IPC_NOERROR:若發送的消息大於size字節,則把該消息截斷,截斷部分將被丟棄,且不通知發送進程。*/
if(msgsnd(msgid, &msg, sizeof(struct msgtype) - sizeof(long), 0) == -1)
{
perror("msgsnd");
exit(1);
}

i++;
sleep(1);
}

sleep(30); //等待消費者進程退出

/*獲取和設置消息隊列的屬性*/
/*cmd IPC_STAT:獲得msgid的消息隊列頭數據到buf中*/
/*cmd IPC_RMID:刪除消息隊列*/
if(msgctl(msgid, IPC_RMID, 0) == -1)
{
perror("msgctl");
exit(1);
}

return 0;
}

/*
*
* Filename: consumer.c
*
* Description: 消費者進程
*
* Version: 1.0
* Created: 09/30/2011 04:52:23 PM
* Revision: none
* Compiler: gcc(g++)
*
* Author: |Zhenghe Zhang|, |[email protected]|
* Company: |Shenzhen XXX Technology Co., Ltd.|
*
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <error.h>

#define BUFFER 10 //定義buf大小

struct msgtype {
long mtype;
char buf1[BUFFER + 1];
char buf2[BUFFER + 1];
long size;
};

int main()
{
key_t msgkey;

/*消息隊列*/
int msgid;
struct msgtype msg;


msgkey = ftok("/home/zhang/shmipcx", 10001);
if(msgkey == -1)
{
perror("ftok");
exit(1);
}

msgid = msgget(msgkey, IPC_EXCL | 0666);
if(msgid == -1)
{
perror("msgget");
exit(1);
}

int i = 0;

while(i < 10) //運行一個consumenr,為 10 ,同時運行兩個consumer進程,為 5
{
memset(msg.buf1, 0, BUFFER + 1);
memset(msg.buf2, 0, BUFFER + 1);
msg.mtype = 1001;
msg.size = -1;

/*從標識符為msqid的消息隊列讀取消息並存於msgp中,讀取後把此消息從消息隊列中刪除*/
/*msgp 存放消息的結構體,結構體類型要與msgsnd函數發送的類型相同*/
/*msgsz 要接收消息的大小,不含消息類型占用的4個字節*/
/*msgtyp 0 接收第一個消息*/
/*msgtyp <0 接收類型等於或者小於msgtyp絕對值的第一個消息*/
/*msgtyp >0 接收類型等於msgtyp的第一個消息*/
/*msgflg 0 阻塞式接收消息,沒有該類型的消息msgrcv函數一直阻塞等待*/
/*msgflg IPC_NOWAIT 如果沒有返回條件的消息調用立即返回,此時錯誤碼為ENOMSG*/
/*msgflg IPC_EXCEPT 與msgtype配合使用返回隊列中第一個類型不為msgtype的消息*/
/*msgflg IPC_NOERROR 如果隊列中滿足條件的消息內容大於所請求的size字節,則把該消息截斷,截斷部分將被丟棄*/
if(msgrcv(msgid, &msg, sizeof(struct msgtype) - sizeof(long), msg.mtype, 0) == -1)
{
perror("msgrcv");
exit(1);
}

printf("msg.mtype = %ld, msg.size = %ld\t", msg.mtype, msg.size);
printf("msg.buf1 = %s, msg.buf2 = %s\n", msg.buf1, msg.buf2);

i++;
sleep(2);
}

return 0;
}

Copyright © Linux教程網 All Rights Reserved