System V 訊息佇列(一)

程式設計-浪子發表於2015-05-23
一、訊息佇列
    1、訊息佇列提供了一個從一個程式向另外一個程式傳送一塊資料的方法
    2、每個資料塊都被認為是有一個型別,接收者程式接收的資料塊可以有不同的型別值
    3、訊息佇列與管道不同的是,訊息佇列是基於訊息的,而管道是基於位元組流的,且訊息佇列的讀取不一定是先入先出。
    4、訊息佇列也有管道一樣的不足,就是每個訊息的最大長度是有上限的(MSGMAX),每個訊息佇列的總的位元組數是有上限的(MSGMNB),系統上訊息佇列的總數也有一個上限(MSGMNI),這三個引數都可以檢視:
    cjl@S405:~$ cat /proc/sys/kernel/msgmax  #一條訊息的長度
    8192
    cjl@S405:~$ cat /proc/sys/kernel/msgmnb  # 一個訊息佇列總的容納長度
    16384
     cjl@S405:~$ cat /proc/sys/kernel/msgmni #系統中建立訊息佇列的最大個數
    1663


二. IPC物件資料結構
    核心為每個IPC物件維護一個資料結構,在<sys/msg.h>標頭檔案中,該標頭檔案在ubuntu系統下的路徑:/usr/include/linux
    
    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) */
}
;
    
四.訊息佇列在核心中的表示

    訊息佇列是用連結串列實現的,這裡需要提出的是MSGMAX指的是一條訊息的純資料大小的上限,下圖是一個 訊息佇列,則其純資料總和不能超過MSGMNB,像這樣一條訊息佇列,系統含有的總數不能超過MSGMNI 個


 
五.訊息佇列函式

    (1) 功能:用來建立和訪問一個訊息佇列

           int msgget(key_t key,  // 某個休息佇列的名字

                            int msgflg);  //由個許可權標誌組成,它們的用法和建立檔案時使用的mode模式標誌時一樣的
    返回值:
        成功返回非負整數,即訊息佇列的標識碼
        失敗:返回-1

    (2)功能:訊息佇列的控制函式

        int msgctl(int msgid,  //msgget函式返回的訊息佇列識別符號

                          int cmd,  // 採取的動作

                        struct msgid_ds *buf);  //

        返回值: 成功返回0

                失敗返回-1

cmd 的取值如下:



會用到的命令

-----------------------------------------------------------------------------------

# ipcs  -q               #檢視IPC訊息佇列命令
#ipcrm -q msgid   # 刪除命令
#ipcrm -Q key      # 刪除命令,如何key為0,則不能刪除
------------------------------------------------------------------------------------
 
    

建立一個訊息佇列: msg_get.c


#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#define ERR_EXIT(m) \
		do \
		{ \
			perror(m); \
			exit(EXIT_FAILURE); \
		}while(0)

int main()
{
	int msgid;
	//msgid = msgget(1234,0666 | IPC_CREAT);
	msgid = msgget(1234,0666 | IPC_CREAT | IPC_EXCL);
	//msgid = msgget(IPC_PRIVATE,0666 | IPC_CREAT | IPC_ECEC);// 建立的不能夠共享的
	//msgid = msgget(IPC_PRIVATE,0666);
	msgid = msgget(1234,0);  // 如果訊息佇列已經存在,則開啟訊息佇列
	if(msgid == -1)
		ERR_EXIT("msgget err");
	printf("msgget success \n");
	printf("msgid=%d\n",msgid);
	return 0;
}

刪除訊息佇列:msg_rmid.c



#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#define ERR_EXIT(m) \
		do \
		{ \
			perror(m); \
			exit(EXIT_FAILURE); \
		}while(0)

int main()
{
	int msgid;
	msgid = msgget(1234,0);  // 如果訊息佇列已經存在,則開啟訊息佇列
	if(msgid == -1)
		ERR_EXIT("msgget err");
	printf("msgget success \n");
	printf("msgid=%d\n",msgid);
	
	msgctl(msgid,IPC_RMID,NULL);
	
	return 0;
}

設定訊息佇列的許可權:msg_set.c

#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#define ERR_EXIT(m) \
		do \
		{ \
			perror(m); \
			exit(EXIT_FAILURE); \
		}while(0)

int main()
{
	int msgid;
	msgid = msgget(1234,0);  // 如果訊息佇列已經存在,則開啟訊息佇列
	if(msgid == -1)
		ERR_EXIT("msgget err");
	printf("msgget success \n");
	printf("msgid=%d\n",msgid);
	
	struct msqid_ds buf;
	msgctl(msgid,IPC_STAT,&buf);  // 必須得先獲取
	sscanf("600","%o",(unsigned int *)&buf.msg_perm.mode);  // 以八進位制輸入到buf
	msgctl(msgid,IPC_SET,&buf);  // 再設定
	return 0;
}

列印訊息佇列的狀態資訊:msg_stat.c

#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#define ERR_EXIT(m) \
		do \
		{ \
			perror(m); \
			exit(EXIT_FAILURE); \
		}while(0)

int main()
{
	int msgid;
	msgid = msgget(1234,0);  // 如果訊息佇列已經存在,則開啟訊息佇列
	if(msgid == -1)
		ERR_EXIT("msgget err");
	printf("msgget success \n");
	printf("msgid=%d\n",msgid);
	
	struct msqid_ds buf;
	msgctl(msgid,IPC_STAT,&buf);
	printf("mode=%o\n",buf.msg_perm.mode);
	printf("bytes=%ld\n",buf.__msg_cbytes);
	printf("number=%d\n",(int)buf.msg_qnum);
	printf("msgmnb=%d\n",(int)buf.msg_qbytes);
	return 0;
}

makefile檔案:

.PHONY:clean all
cc=gcc
CFLAGS=-Wall -g
BIN=msg_get msg_rmid msg_stat msg_set
all:$(BIN)
%.o:%.c
	$(cc) $(CFLAGS) -c $< -o $@
clean:
	rm -f *.o $(BIN)


    
   

相關文章