說明:只供學習交流,裝載請註明出處
六,msgsnd函數
創建完消息隊列後,爲了通過消息隊列進行進程間的通信,信息的發送方必須向消息隊列發送信息。信息的接收方需要從消息隊列中接收消息。發送消息和接收消息使用的函數分別是msgsnd函數和msgrcv函數。msgsnd函數的具體信息如下表:
msgsnd函數
頭文件 |
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> |
||
函數原型 |
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); |
||
返回值 |
成功 |
失敗 |
是否設置errno |
0 |
-1 |
是 |
說明:msgsnd函數用於向消息隊列中發送消息。參數msqid爲要將消息發送到的消息隊列。參數msgp爲指向msgbuf結構體的指針,其定義如下:
struct msgbuf
{
longmtype; //消息類型,可以爲大於0的任意整數
char mtext[1]; //消息文本,文本的大小由msgsnd函數中的參數msgsz確定
};
參數msgsz爲所發送消息的字節數。msgflg可以爲0(忽略該參數)或使用IPC_NOWAIT。
如果消息隊列中有足夠的空間,msgsnd函數立即返回,並將msgp指向的消息添加到指定消息隊列中。消息隊列可容納的最大消息量在msg_bytes中給出,該值在創建消息隊列時被初始化爲MSGMNB,當然可以通過msgctl函數修改該限制。
如果消息隊列已經達到了最大消息量,msgsnd函數將阻塞(參數msgflg沒有使用IPC_NOWAIT情況下,如果使用了該參數,msgsnd將調用失敗,同時,將errno設置爲EAGAIN),直到消息隊列中有足夠的空間。
成功調用msgsnd函數後,將更新msqid_ds結構體中的如下成員:
msg_lspid:調用進程的進程號。
msg_qnum:加1
msg_stime:設置爲當前的時間。
錯誤信息:
EACCES:調用msgsnd函數的進程沒有向消息隊列發送消息的權限。
EAGAIN:消息隊列達到最大信息量,同時msgflg中使用了IPC_NOWAIT參數。
EFAULT:msgp指向的非法地址空間。
EIDRM:消息隊列被刪除。
EINTR:msgsnd函數調用被信號中斷。
EINVAL:非法的msqid值、mtype爲負數或msgsz不合法(小於0或大於系統規定的MSGMAX值)。
ENOMEM:系統空間不足。
實例:
程序爲使用msgsnd函數的實例。程序首先調用msgsnd函數,向消息隊列中發送消息,然後,調用msgctl函數來獲得消息隊列的相關信息,以確認消息隊列中是否存在發送來的消息。具體代碼如下:
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <string.h>
typedef struct
{
long mtype;
char mtext[BUFSIZ];
}msg_info;
//創建消息隊列
int creat_msg_queue()
{
key_t key;
int proj_id;
int msqid;
struct msqid_ds buffer;
proj_id = 3;
key = ftok("./hello", proj_id);
if (key == -1)
{
perror("Cannot generate the IPC key");
return (-1);
}
msqid = msgget(key, IPC_CREAT|0660);
if (msqid == -1)
{
perror("Cannot create message queue resource");
return (-1);
}
return (msqid);
}
//給指定消息隊列發送消息
int send_msg(int msqid, char *msg)
{
int result;
msg_info buf;
buf.mtype = 100;
strcpy(buf.mtext, msg);
result = msgsnd(msqid, &buf, strlen(msg), 0);
if (result == -1)
{
perror("Cannot send message to the message queue");
}
return (result);
}
//顯示消息隊列的信息
int show_msg_queue_stat(int msqid)
{
struct msqid_ds buffer;
int flg;
flg = msgctl(msqid, IPC_STAT, &buffer);
if (flg == -1)
{
perror("Cannot get status of the message queue");
return (-1);
}
printf("======Message Queue Info======\n");
printf("effective user of id : %d\n", buffer.msg_perm.uid);
printf("effective group of id : %d\n", buffer.msg_perm.gid);
printf("message queue's creator user id : %d\n", buffer.msg_perm.cuid);
printf("message queue's creator user id : %d\n", buffer.msg_perm.cgid);
printf("access mode : %x\n", buffer.msg_perm.mode);
printf("Maximum number of bytes allowed in message queue: %d\n",
(int)buffer.msg_qbytes);
printf("Current number of bytes in message queue(non-standard) : %d\n",
(long unsigned int)buffer.__msg_cbytes);
printf("Current number of message in message queue : %d\n",
(msgqnum_t)buffer.msg_qnum);
return (0);
}
int main(void)
{
int msqid;
if (msqid = creat_msg_queue()<0)
{
printf("Create msg queue fail\n");
return (-1);
}
if (send_msg(msqid, "test message") < 0)
{
printf("Send message failure\n");
return (-1);
}
if (show_msg_queue_stat(msqid) < 0)
{
printf("Show message queue fail\n");
return (-1);
}
return (0);
}
運行結果:
[root@localhost test]# ./msgsnd
======Message Queue Info======
effective user of id : 0
effective group of id : 0
message queue's creator user id : 0
message queue's creator user id : 0
access mode : 1b0
Maximum number of bytes allowed in message queue: 65536
Current number of bytes in message queue(non-standard) : 12
Current number of message in message queue : 1
[root@localhost test]# ipcs -q
------ Message Queues --------
key msqid owner perms used-bytes messages
0x03021077 0 root 660 12 1
[root@localhost test]#
七,msgrcv函數
要接收消息隊列中的消息,需要使用msgrcv函數。該函數的具體信息如下表:
頭文件 |
#include <sys/ipc.h> #include <sys/msg.h> #include <sys/types.h> |
||
函數原型 |
size_t msgrcv(int msqid, void *msgp, long msgtyp, int msgflg); |
||
返回值 |
成功 |
失敗 |
是否設置errno |
收到消息的字節數 |
-1 |
是 |
函數功能:msgrcv函數從msgid代表的消息隊列中讀取一個消息,並將消息存儲在msgp指向的緩衝結構中。該緩衝結構的定義類似於msgbuf結構體。
參數說明:msqid爲要成中讀取消息的消息隊列標識符;msgp爲指向消息內容的指針;msgsz爲msgbuf結構體中mtext成員的長度(即消息內容的長度);msgtyp爲請求的消息類型,如果msgtyp爲0,消息隊列中的第一條消息將被讀取,而不管類型。如果msgtyp大於0,消息隊列中同類型的消息將被讀取。如果在msgflg中設置了MSG_RXCEPT位,將讀取出指定類型的其他消息。如果msgtyp小於0,將讀取絕對值小於msgtyp的消息; msgflg爲指定的處理方式,可以取一下值:
IPC_NOWAIT:如果沒有滿足條件的消息,調用立即返回,此時,errno爲ENOMSG。
IPC_EXCEPT:與msgtyp>0配合使用,返回隊列中第一個類型不爲msgtyp的消息。
IPC_NOERROR:如果隊列中滿足條件的消息內容大於所請求的msgsz字節,則把該消息截斷,截斷部分將丟失。
如果消息隊列中沒有要獲得的消息類型(有參數msgtyp指定),且msgflg參數沒有設置IPC_NOWAIT位,msgrcv函數將處於阻塞狀態,直到以下情況發生:
(1):消息隊列中收到了進程要獲得的消息。
(2):消息隊列被刪除,msgrcv系統調用失敗。
(3):調用過程中接收到了中斷。
當成功獲得所需消息後,將更新msqid_ds結構體中的如下成員:
msg_lrpid:被設置成調用msgrcv函數的進程。
msg_qnum:減1。
msg_rtime:被設置成系統當前時間。
錯誤信息:
E2BIG:接收到消息的長度超過參數msgsz中指定的長度,同時,參數msgflg沒有設置MSG_NOERROR位。
EACCES:進程無讀取消息隊列中消息的權限。
EAGAIN:消息隊列中無所要獲得類型的消息,且msgflg沒有設置IPC_NOWAIT位。
EFAULT:參數msgp執行非法地址空間。
EIDRM:當進程處於阻塞狀態等待要獲得類型的消息時,消息隊列被刪除。
EINTR:當進程處於阻塞狀態等待要獲得類型的消息時,接收到信號。
EINVAL:非法的msqid值或msgsz小於0。
ENOMSG:msgflg中指定了IPC_NOWAIT位,而消息隊列中沒有要獲取的消息。
實例:
程序通過調用msgrcv函數實現了讀取消息隊列中指定消息的功能。讀取消息隊列中信息的函數爲recv_msg,函數的參數意義如下:
(1):msqid:消息隊列標識符。
(2):msg_type:消息類型,該消息類型與調用時發送的類型要一致。
(3):msg:接收到消息內容將保存在該指針的空間中。
具體代碼如下:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
typedef struct
{
long mtype;
char mtext[BUFSIZ];
}msg_info;
int recv_msg(int msqid, int msg_type, char *msg)
{
int result;
msg_info buffer;
result = msgrcv(msqid, &buffer, BUFSIZ, msg_type, 0);
if (result == -1)
{
perror("Cannot receive message from the queue");
}
strcpy(msg, buffer.mtext);
return (result);
}
int main(int argc, char *argv[])
{
char buf[BUFSIZ] = {'\0'};
int msqid;
int msg_type;
int result;
if (argc != 3)
{
printf("Usage: %s msqid message_type");
return (-1);
}
msqid = atoi(argv[1]);
msg_type=atoi(argv[2]);
result = recv_msg(msqid, msg_type, buf);
if (result == -1)
{
printf("Cannot get message\n");
return (-1);
}
else
{
printf("Message queue id: %d message type : %d message : %s\n",
msqid, msg_type, buf);
}
return (0);
}
運行結果:
[root@localhost test]# ./msgrcv 0 100
Message queue id: 0 message type : 100 message : test message
[root@localhost test]# ipcs -q
------ Message Queues --------
key msqid owner perms used-bytes messages
0x03021077 0 root 660 0 0
[root@localhost test]#