15_ipc中的消息隊列

消息隊列

 消息隊列提供了一個從一個進程向另外一個進程發送一塊數據的方法
 每個數據塊都被認爲是有一個類型,接收者進程接收的數據塊可以有不同的類型值
 消息隊列也有管道一樣的不足,就是每個消息的最大長度是有上限的(MSGMAX),每個消息隊列的總的字節數是有上限的(MSGMNB),系統上消息隊列的總數也有一個上限(MSGMNI)

對比:
管道:流管道 先進先出
消息:有邊界可以後進入、先出來

消息大小三大限制
cat /proc/sys/kernel/msgmax 最大消息長度 限制
cat /proc/sys/kernel/msgmnb 消息隊列總的字節數
cat /proc/sys/kernel/msgmni 消息條目數

IPC對象數據結構


	內核爲每個IPC對象維護一個數據結構
struct ipc_perm {
	key_t          __key;       /* Key supplied to xxxget(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 */
};

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) */
};


消息隊列在內核中的表示在這裏插入圖片描述

消息隊列函數


	#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);

msgget函數

 功能:用來創建和訪問一個消息隊列
 原型
 int msgget(key_t key, int msgflg);
 參數
 key: 某個消息隊列的名字
 msgflg:由九個權限標誌構成,它們的用法和創建文件時使用的mode模式標誌是一樣的
 返回值:成功返回一個非負整數,即該消息隊列的標識碼;失敗返回-1

msgctl函數

 功能:消息隊列的控制函數
 原型
 int msgctl(int msqid, int cmd, struct msqid_ds *buf);
 參數
 msqid: 由msgget函數返回的消息隊列標識碼
 cmd:是將要採取的動作,(有三個可取值)
 返回值:成功返回0,失敗返回-1

cmd:將要採取的動作(有三個可取值),分別如下:
在這裏插入圖片描述

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;
char mtext[100];
}

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

dm01_msgbase.c

//打開消息隊列,若不存在,則報錯
#if 0
int test()
{
	int msgid;
	// int msgget(key_t key, int msgflg);
	//msgflag如果只寫權限,表示要打開文件,這個文件必須存在
	msgid = msgget(0x1234, 0666);//0表示8進制
	if (msgid == -1) 
	{
		if (errno == ENOENT) 
		{
			printf("自己檢查錯誤, 消息隊列不存在\n");
		}
		perror("msgget");
		return -1;
	}
	system("ipcs -q");
	return 0;
}
#endif
/*
	hzmct@U-64:/study/linuxtest/day06/ipc_queue$ ./dm01_msgbase
	自己檢查錯誤, 消息隊列不存在
	msgget: No such file or directory
*/
//打開消息隊列,若存在,使用舊的,若不存在,則創建
#if 0
int test()
{
	int msgid;
	msgid = msgget(0x1234, 0666|IPC_CREAT);
	if (msgid == -1) 
	{
		if (errno == ENOENT) 
		{
			printf("自己檢查錯誤, 消息隊列不存在\n");
		}
		perror("msgget");
		return -1;
	}
	printf("創建消息隊列成功\n");
	return 0;
}
#endif

//打開消息隊列,若存在,使用舊的,若不存在,則創建
//獲取消息隊列的id
#if 0
int test()
{
	int msgid;
	msgid = msgget(0x1234, 0666|IPC_CREAT);
	if (msgid == -1) 
	{
		if (errno == ENOENT) 
		{
			printf("自己檢查錯誤, 消息隊列不存在\n");
		}
		perror("msgget");
		return -1;
	}
	printf("msgid:%d\n", msgid);
	printf("創建消息隊列成功\n");
	return 0;
}
#endif
//若 IPC_CREAT and IPC_EXCL 在一起。。。。
//若不存在,則創建
//打開消息隊列,若存在,則提示已經存在
//單獨使用IPC_EXCL沒有任何意義
#if 0
int test()
{
	int msgid;
	msgid = msgget(0x1234, 0666|IPC_CREAT|IPC_EXCL);
	if (msgid == -1) 
	{
		if (errno == ENOENT) 
		{
			printf("自己檢查錯誤, 消息隊列不存在\n");
		}
		
		if (errno == EEXIST) 
		{
			printf("自己檢查錯誤, 消息隊列已經存在\n");
		}
		perror("msgget");
		return -1;
	}
	printf("msgid:%d\n", msgid);
	printf("創建消息隊列成功\n");
	return 0;
}
#endif
/*
	IPC_PRIVATE創建消息隊列,只能在自己家族中使用
	不能在沒有血緣關係的進程間用
	當使用了 IPC_PRIVATE,則 IPC_CREAT and IPC_EXCL不起作用
	。
	每次執行程序,msqid都不一樣
	
	hzmct@U-64:~$ ipcs -q

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages             
0x00000000 32769      hzmct      666        0            0           
0x00000000 65538      hzmct      666        0            0           
0x00000000 98307      hzmct      666        0            0           
0x00000000 131076     hzmct      666        0            0  
*/
#if 0
int test()
{
	int msgid;
	msgid = msgget(IPC_PRIVATE, 0666);
	if (msgid == -1) 
	{
		if (errno == ENOENT) 
		{
			printf("自己檢查錯誤, 消息隊列不存在\n");
		}
		
		if (errno == EEXIST) 
		{
			printf("自己檢查錯誤, 消息隊列已經存在\n");
		}
		perror("msgget");
		return -1;
	}
	printf("msgid:%d\n", msgid);
	printf("創建消息隊列成功\n");
	return 0;
}
#endif

int main()
{
	test();
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章