標籤:linux ipc 訊息佇列 處理序間通訊 cc++
訊息佇列函數
#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h> int msgget(key_t key, int msgflg); int msgctl(int msqid, int cmd, struct msqid_ds *buf); int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
msgctl函數
功能:擷取/設定訊息佇列的資訊
原型:
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
參數:
msqid: 由msgget函數返回的訊息佇列標識碼
cmd:是將要採取的動作(見下)
傳回值:
成功返回0,失敗返回-1
cmd:將要採取的動作(有三個可取值),分別如下:
訊息佇列資料結構
struct msqid_ds{ struct ipc_perm msg_perm; /* Ownership and permissions */ time_t msg_stime; /* Time of last msgsnd(2) */ time_t msg_rtime; /* Time of last msgrcv(2) */ time_t msg_ctime; /* Time of last change */ unsigned long __msg_cbytes; /* Current number of bytes in queue (nonstandard) */ msgqnum_t msg_qnum; /* Current number of messages in queue */ msglen_t msg_qbytes; /* Maximum number of bytes allowed in queue */ pid_t msg_lspid; /* PID of last msgsnd(2) */ pid_t msg_lrpid; /* PID of last msgrcv(2) */};
Ipc_perm資料結構
struct ipc_perm{ key_t __key; /* Key supplied to msgget(2) */ uid_t uid; /* Effective UID of owner */ gid_t gid; /* Effective GID of owner */ uid_t cuid; /* Effective UID of creator */ gid_t cgid; /* Effective GID of creator */ unsigned short mode; /* Permissions */ unsigned short __seq; /* Sequence number */};
//實踐:IPC_STATint main(){ int msgid = msgget(0x1234, 0666); if (msgid == -1) { err_exit("msgget error"); } struct msqid_ds buf; if (msgctl(msgid,IPC_STAT,&buf) == -1) { err_exit("msgctl error"); } printf("buf.msg_perm.mode = %o\n",buf.msg_perm.mode); //%o以八進位列印 cout << "buf.__msg_cbytes = " << buf.__msg_cbytes << endl; cout << "buf.msg_qbytes = " << buf.msg_qbytes << endl; cout << "buf.msg_lspid = " << buf.msg_lspid << endl;}
//實踐:IPC_SET,一般需要先擷取,然後再設定int main(){ int msgid = msgget(0x1234, 0666); if (msgid == -1) { err_exit("msgget error"); } //擷取訊息佇列的屬性 struct msqid_ds buf; if (msgctl(msgid,IPC_STAT,&buf) == -1) { err_exit("msgctl get error"); } //設定訊息佇列的屬性 buf.msg_perm.mode = 0644; if (msgctl(msgid,IPC_SET,&buf) == -1) { err_exit("msgctl set error"); } //擷取並列印 if (msgctl(msgid,IPC_STAT,&buf) == -1) { err_exit("msgctl get error"); } printf("buf.msg_perm.mode = %o\n",buf.msg_perm.mode); //%o以八進位列印}
//實踐:IPC_RMID,刪除訊息佇列/**說明:可以通過在多個視窗上運行幾個該程式,測試出: 訊息佇列並沒有運用”引用計數”的功能!*/int main(){ int msgid = msgget(0x1234, 0666); if (msgid == -1) { err_exit("msgget error"); } int choice = 0; cout << "Please input Your choice: 0-delete, other-continue: "; cin >> choice; if (!choice) { //delete msg if (msgctl(msgid,IPC_RMID,NULL) == -1) { err_exit("msgctl IPC_RMID error"); } else { cout << "msgid = " << msgid << ", IPC_RMID OK!" << endl; } }}
訊息的發送和接收
msgsnd函數
功能:把一條訊息添加到訊息佇列中
原型
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
參數
msgid: 由msgget函數返回的訊息佇列標識碼
msgp:是一個指標,指標指向準備發送的訊息,
msgsz:是msgp指向的訊息長度,這個長度不含儲存訊息類型的那個long int長整型
msgflg:控制著當前訊息佇列滿或到達系統上限時將要發生的事情
傳回值:
成功返回0;失敗返回-1
msgflg=IPC_NOWAIT表示隊列滿不等待,返回EAGAIN錯誤。
訊息結構在兩方面受到制約。首先,它必須小於系統規定的上限值;其次,它必須以一個long int長整數開始,接收者函數將利用這個長整數確定訊息的類型
訊息結構參考形式如下:
struct msgbuf{ long mtype; /* message type, must be > 0 */ char mtext[1]; /* message data */};
//實踐/**發送結構*/struct msgBuf{ long mtype; /* message type, must be > 0 */ char mtext[1024]; /* message data */};int main(){ int msgid = msgget(0x1234,0666|IPC_CREAT); if (msgid == -1) { err_exit("msgget error"); } //初始化訊息結構 struct msgBuf myBuffer; myBuffer.mtype = 1; strcpy(myBuffer.mtext,"Hello XiaoFang!"); //向訊息佇列發送訊息 if (msgsnd(msgid,&myBuffer,strlen(myBuffer.mtext),IPC_NOWAIT) == -1) { err_exit("msgsnd error"); } return 0;}
msgrcv函數
功能:是從一個訊息佇列接收訊息
原型
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
參數
msgid: 由msgget函數返回的訊息佇列標識碼
msgp:是一個指標,指標指向準備接收的訊息,
msgsz:是msgp指向的訊息長度,這個長度不含儲存訊息類型的那個long int長整型
msgtype:它可以實現接收優先順序的簡單形式
msgflg:控制著隊列中沒有相應類型的訊息可供接收時將要發生的事
傳回值:
成功->返回實際放到接收緩衝區裡去的位元組數;失敗->返回-1
msgtyp |
msgtyp=0 |
返回隊列第一條資訊 |
msgtyp>0 |
返回隊列第一條類型等於msgtype的訊息 |
msgtyp<0 |
返回隊列第一條類型小於等於msgtype絕對值的訊息,並且是滿足條件的訊息類型最小的訊息 |
msgflg |
msgflg=IPC_NOWAIT |
隊列沒有可讀訊息不等待,返回ENOMSG錯誤。 |
msgflg=MSG_NOERROR |
訊息大小超過msgsz時被截斷 |
msgtyp>0且msgflg=MSG_EXCEPT |
接收類型不等於msgtype的第一條訊息 |
//實踐:訊息發送int main(){ int msgid = msgget(0x1234,0666|IPC_CREAT); if (msgid == -1) { err_exit("msgget error"); } struct msgBuf myBuffer; for (int i = 0; i < 128; ++i) { myBuffer.mtype = i+1; sprintf(myBuffer.mtext,"Hello, My number is %d",i+1); if (msgsnd(msgid,&myBuffer,strlen(myBuffer.mtext),IPC_NOWAIT) == -1) { err_exit("msgsnd error"); } } return 0;}
//實踐:訊息接收:從隊首不斷的取資料int main(){ int msgid = msgget(0x1234,0666); if (msgid == -1) { err_exit("msgget error"); } //從隊首不斷的取資料,連續取10個 struct msgBuf myBuffer; for (int i = 0; i < 10; ++i) { int recvBytes = 0; if ((recvBytes = msgrcv(msgid,&myBuffer,sizeof(myBuffer.mtext),0,IPC_NOWAIT)) == -1) { err_exit("msgrcv error"); } else { cout << "receive recvBytes = " << recvBytes << endl; cout << "myBuffer.mtype = " << myBuffer.mtype << endl; cout << "\t" << myBuffer.mtext << endl; } } cout << "strlen(myBuffer.mtext) = " << strlen(myBuffer.mtext) << endl; return 0;}
Linux訊息佇列實踐(2)