程序間的通訊——訊息佇列篇
什麼是訊息佇列?
訊息佇列就是一個訊息的連結串列。可以把訊息看作一個記錄,具有特定的格式以及特定的優先順序。對訊息佇列有寫許可權的程序可以向訊息佇列中按照一定的規則新增新訊息;對訊息佇列有讀許可權的程序則可以從訊息佇列中讀走訊息。訊息佇列是隨核心持續的。也就是說程序的退出,如果不自主去釋放資源,訊息佇列是會悄無聲息的存在的。訊息佇列與管道不同的是,訊息佇列是基於訊息的, 而管道是基於位元組流的,且訊息佇列的讀取不一定是先入先出。訊息佇列與命名管道有一 樣的不足,就是每個訊息的最大長度是有上限的(MSGMAX),每個訊息佇列的總的位元組數是有上限的(MSGMNB),系統上訊息佇列的總數也有一個上限
程序通訊我們有了管道,為什麼還要引入訊息佇列呢?
因為根據管道的特性,我們知道其在一定程度上存在或多或少的侷限性,首先匿名管道以及命名管道是隨程序的,程序的退出,意味著管道生命週期的結束;其次,管道傳送資料時以無格式位元組流的形式傳送,這有時會給程式的開發帶來不便;再者,擔當資料傳送媒介的管道,其緩衝區的大小也有較大的限制。所以作為IPC方式下的另一種應用於程序間通訊的訊息佇列方式便應運而生了。
IPC物件資料結構:
//核心為每個IPC物件維護了一個數據結構
struct ipc_perm
{
__kernel_key_t key;//key值是訊息佇列的一個驗證碼(我理解為暗號,首先一個程序要向訊息佇列放入一個東西,得先生成一個key值,這個key值是函式計算得來的,輸入值確定會固定得到一個key值,而又有一個程序需要取剛才程序放的東西,這時候就得暗號匹配才能取。)
__kernel_uid_t uid;
__kernel_gid_t gid;
__kernel_uid_t cuid;
__kernel_gid_t cgid;
__kernel_mode_t mode; //許可權
unsigned short seq;
};
訊息佇列結構:
struct msqid_ds {
struct ipc_perm msg_perm;
struct msg *msg_first; /* first message on queue,unused */
struct msg *msg_last; /* last message in queue,unused */
__kernel_time_t msg_stime; /* last msgsnd time */
__kernel_time_t msg_rtime; /* last msgrcv time */
__kernel_time_t msg_ctime; /* last change time */
unsigned long msg_lcbytes; /* Reuse junk fields for 32 bit */
unsigned long msg_lqbytes; /* ditto */
unsigned short msg_cbytes; /* current number of bytes on queue */
unsigned short msg_qnum; /* number of messages in queue */
unsigned short msg_qbytes; /* max number of bytes on queue */
__kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */
__kernel_ipc_pid_t msg_lrpid; /* last receive pid */
};
和訊息佇列有關的函式:
- 生成key值
key_t ftok(const char *pathname, int proj_id);
- 用來建立或者訪問一個訊息佇列
int msgget(key_t key, int msgflg);
//key 上面解釋過了,相當於一個暗號由ftok函式建立
//msgflg: IPC_CREAT:建立新的訊息佇列。 IPC_EXCL:與IPC_CREAT一同使用,表示如果要建立的訊息佇列已經存在,則返回錯誤。 IPC_NOWAIT:讀寫訊息佇列要求無法滿足時,不阻塞。
//返回值: 呼叫成功返回佇列識別符號,否則返回-1.
- 訊息佇列的控制函式
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
//msqid:有msgget返回的標識碼
//cmd:將要採取的動作,IPC_STAT把msqid_ds結構的資料設定為訊息佇列的當前關聯值, IPC_SET在許可權允許的情況下,吧訊息佇列的當前關聯值設定為msqid_ds資料結構中給出的值,IPC_RMID刪除訊息佇列
- 插入一條訊息到訊息佇列
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
//msqid:由msgget函式返回的訊息佇列標識碼
//msgp:指向準備傳送訊息的指標
//msgsz:是msgp的長度
//msgflg:控制這當前訊息佇列是否滿或者達到系統上限
//返回值成功為0;失敗為-1
- 從訊息佇列接收一個訊息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
//msqid:由msgget函式返回的訊息佇列標識碼
//msgp:指向準備接收訊息的指標
//msgsz:是msgp的長度
//msgtyp:它可以實現接收優先順序的簡單形式
//msgflg:控制這當前訊息佇列是否滿或者達到系統上限
//返回值成功為實際接收到接收快取區的字元個數;失敗為-1
說明:
msgtyp等於0 則返回佇列的最早的一個訊息。
msgtyp大於0,則返回其型別為mtype的第一個訊息。
msgtyp小於0,則返回其型別小於或等於mtype引數的絕對值的最小的一個訊息。
msgflg:這個引數依然是是控制函式行為的標誌,取值可以是:0,表示忽略;IPC_NOWAIT,如果訊息佇列為空,則一個ENOMSG,並將控制權交回呼叫函式的程序。如果不指定這個引數,那麼程序將被阻塞直到函式可以從佇列中得到符合條件的訊息為止。如果一個client 正在等待訊息的時候佇列被刪除,EIDRM 就會被返回。如果程序在阻塞等待過程中收到了系統的中斷訊號,EINTR 就會被返回*。MSG*_NOERROR,如果函式取得的訊息長度大於msgsz,將只返回msgsz 長度的資訊,剩下的部分被丟棄了。如果不指定這個引數,E2BIG 將被返回,而訊息則留在佇列中不被取出。當訊息從佇列內取出後,相應的訊息就從佇列中刪除了。
例項:
功能是實現倆個視窗之間的相互通訊:
最終的成果圖
具體實現如下:
msgges.h:
#pragma once
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
//這倆個巨集定義是生成key值
#define PATH "."
#define NUM 0x6666
//
#define SERVER_TYPE 1
#define CLIENT_TYPE 2
//訊息佇列中訊息的結構體
struct msgbuf{
long mtype;//上面進行巨集定義的SERVER_TYPE與CLINENT_TYPE就是這個
char mtext[1024];
};
int createMsgQueue();
int getMsgQueut();
int destroyMsgQueut(int msgid);
int sendMsg(int msgid,int who,char *msg);
int recvMsg(int msgid,int recvType,char out[]);
msgges.c:
#include "msgges.h"
//建立一個訊息佇列,如果已經有了,返回錯誤
int createMsgQueue()
{
key_t key = ftok(PATH,NUM);//生成key值(暗號)
if(key < 0)
{
perror("ftok");
return -1;
}
int msgid = msgget(key, IPC_CREAT|IPC_EXCL|0666);
if(msgid < 0)
{
perror("msgget");
return -1;
}
return msgid;
}
//建立一個訊息佇列,如果已經有訊息隊列了,返回已經有的訊息佇列msgid
int getMsgQueue()
{
key_t key = ftok(PATH,NUM);
if(key < 0)
{
perror("ftok");
return -1;
}
int msgid = msgget(key, IPC_CREAT);
if(msgid < 0)
{
perror("msgget");
return -1;
}
return msgid;
}
//刪除訊息佇列
int destroyMsgQueue(int msgid)
{
printf("111\n");
if(msgctl(msgid,IPC_RMID,NULL) < 0)
{
perror("msgctl");
return -1;
}
return 0;
}
//往訊息佇列裡發資料
int sendMsg(int msgid,int who,char *msg)
{
struct msgbuf buf;
buf.mtype = who;
strcpy(buf.mtext,msg);
if(msgsnd(msgid,(void*)&buf,sizeof(buf.mtext),0) < 0)
{
perror("msgsnd");
return -1;
}
return 0;
}
//從訊息佇列裡取資料
int recvMsg(int msgid,int recvType, char out[])
{
struct msgbuf buf;
if(msgrcv(msgid,(void*)&buf,sizeof(buf.mtext),recvType,0) < 0)
{
perror("msgrcv");
return -1;
}
strcpy(out,buf.mtext);
return 0;
}
server.c:
#include "msgges.h"
int main()
{
int msgid = createMsgQueue();
char buf[1024];
while(1)
{
buf[0] = 0;
recvMsg(msgid,CLIENT_TYPE,buf);
printf("小明:%s\n",buf);
printf("你:");
fflush(stdout);
ssize_t s = read(0,buf,sizeof(buf));
if(s > 0)
{
buf[s-1] = 0;
sendMsg(msgid,SERVER_TYPE,buf);
}
}
destroyMsgQueue(msgid);
return 0;
}
client.c:
#include "msgges.h"
int main()
{
int msgid = getMsgQueue();
char buf[1024];
while(1)
{
buf[0] = 0;
printf("你:");
fflush(stdout);
ssize_t s = read(0,buf,sizeof(buf));
if(s > 0)
{
buf[s-1] = 0;
sendMsg(msgid,CLIENT_TYPE,buf);
}
recvMsg(msgid,SERVER_TYPE,buf);
printf("張三:%s\n",buf);
}
return 0;
}
Makefile:
.PHONY:all
all:client server
client:client.c msgges.c
gcc $^ -o [email protected];
server:server.c msgges.c
gcc $^ -o [email protected];
.PHONY:clean
clean:
rm -f client server
最後如果你出現了下面的錯誤:
解決辦法如下:
造成這個原因是,你只要編譯通過,並且運行了 你再用ctrl+c 終止掉程序,程序不會走這個函式的destroyMsgQueue(msgid); 一旦你發出ctrl+c訊號,作業系統就會馬上殺死該程序。這樣就會造成IPC沒有及時被回收。想要解決這個問題我們可以將ctrl+c 的執行函式改為destroyMsgQueue(msgid); 並且執行完後退出即可。
相關推薦
php程序間通訊--訊息佇列
首先我們來看一下如何建立一個訊息佇列。 //建立訊息佇列 $msg_key = ftok( __FILE__, 'a' ); $msg_queue = msg_get_queue( $msg_key, 0666 ); 在php中通過這兩句話就可以建立一個訊息佇列。 ftok 函式,是可以
Linux關於程序間通訊訊息佇列
訊息佇列概念 訊息佇列提供了一個從一個程序向另外一個程序傳送一塊資料的方法 每個資料塊都被認為是有一個型別,接收者程序接收的資料塊可以有不同的型別值 訊息佇列也有管道一樣的不足,就是每個資料塊的最大長度是有上限的,系統上全體佇列的最大總長度也有一個上限 訊息佇列函式操作
python 多程序間通訊 訊息佇列
import multiprocessing import time #使用佇列,將訊息寫進佇列,需要的程序到佇列取 #佇列由父程序建立,子程序共享佇列 def write(qe): print("啟動子程序 write") for chr in ['A','B','C','D
程序間通訊——訊息佇列
每個程序各自具有不同的使用者地址空間,任何一個程序的全域性變數在另外一個程序中看不到;所以程序之間要交換資料必須通過核心,在核心中開闢一塊緩衝區,程序1把資料從使用者空間拷到核心緩衝區,程序2再從核心緩
一步一步學linux之程序間通訊——訊息佇列
一、什麼是訊息佇列:訊息佇列提供了一種程序與程序間傳送資料塊的一種方法,每個資料塊含有一個型別,接收程序可以獨立地接收含有不同型別的資料結構,可以通過傳送訊息來避免同步和阻塞問題。訊息佇列有最大長度限制 在分散式計算環境下,訊息佇列是為了對異構網路環境下的分散式應
Linux程序間通訊——訊息佇列應用例項
訊息佇列是訊息的連結表,包括Posix訊息佇列system V訊息佇列。有足夠許可權的程序可以向佇列中新增訊息,被賦予讀許可權的程序則可以讀走佇列中的訊息。訊息佇列克服了訊號承載資訊量少,管道只能承載無格式位元組流以及緩衝區大小受限等缺點。下面是兩個測試模組接收模組m
System V程序間通訊---訊息佇列
一、訊息佇列模型 訊息佇列是訊息的鏈式佇列,下圖即為訊息佇列模型… 1、訊息佇列的基本屬性 struct msqid_ds { struct msqid_ds { struct ipc_perm msg_perm;
PHP 程序間通訊——訊息佇列(msg_queue)
PHP 程序間通訊——訊息佇列 本文不涉及PHP基礎庫安裝。詳細安裝說明,請參考官網,或期待後續部落格分享。 1、訊息佇列函式準備 <?php //生成一個訊息佇列的key $msg_key = ftok(__FILE__, 'a'); //產生一個訊息佇列
linux程序間通訊--訊息佇列相關函式(ftok)詳解
ipc_perm中mode的含義 操作者 讀 寫 可讀可寫 使用者 0400 0200 0600 組 0040 0020 0060 其他 0004 0002 0006 5. IPC物件的建立許可權 msgget、semget、sh
Linux 程序間通訊——訊息佇列實現雙向通訊
函式: key_t ftok(const char *filename, int proj_id); 通過檔名和專案號獲得System V IPC鍵值(用於建立訊息佇列、共享記憶體所用) proj_id:專案號,不為0即可 返回:成功則返回鍵值,失敗則返回-1 函式: in
程序間的通訊——訊息佇列篇
什麼是訊息佇列? 訊息佇列就是一個訊息的連結串列。可以把訊息看作一個記錄,具有特定的格式以及特定的優先順序。對訊息佇列有寫許可權的程序可以向訊息佇列中按照一定的規則新增新訊息;對訊息佇列有讀許可權的程序則可以從訊息佇列中讀走訊息。訊息佇列是隨核心持續的。也
程序間通訊:佇列,管道,檔案,共享記憶體,訊號量,事件,互斥鎖,socket
2017/11/4 程序間通訊,程序池 程序間通訊(IPC,inter-process communication):生產程序生產食物,消費程序購買食物,消費程序一直監視生產狀況,只要一有食物就將其取出來,如果取到食物None,兩者關係結束,於是主程序也結束。 遠端過程呼叫
程序間通訊——訊息傳遞(訊號量同步PV操作)
【申明:本文僅限於自我歸納總結和相互交流,有紕漏還望各位指出。 聯絡郵箱:[email protected]】 在多工作業系統環境下,多程序/多執行緒間同時執行,並且這些程序之間存在一定的關聯,多個程序/執行緒可能為了完成同一個任務相互協作,這就是程序之間的同步,
程序間通訊之管道篇
何為程序間通訊 每個程序各自有不同的使用者地址空間,任何一個程序的全域性變數在另一個程序中都是看不到的。所以程序之間如果要交換資料就必須通過核心。 在核心中開闢一塊緩衝區,程序1把資料從使用者空間拷到核心緩衝區,程序2再從核心緩衝區把資料讀走,核心提供的這種機制稱為程序間
Android native程序間通訊例項-binder篇之——HAL層訪問JAVA層的服務
有一天在群裡聊天的時候,有人提出一個問題,怎樣才能做到HAL層訪問JAVA層的介面?剛好我不會,所以做了一點研究。 之前的文章末尾部分說過了service call 可以用來除錯系統的binder服務。 傳送門: Android native程序間通訊例項-binder篇之&mda
boost程序間通訊常用開發一篇全(訊息佇列,共享記憶體,訊號)
本文概要: 敏捷開發大家想必知道而且評價甚高,縮短開發週期,提高開發質量。將大工程獨立為不同的小app開發,整個開發過程,程式可用可測,所以提高了整體的質量。基於這種開發模式和開發理念,程序間通訊必然是童鞋們必掌握技能之一了,而boost庫是眾多庫中平臺支援
Linux:程序間通訊(匿名管道命名管道)(共享記憶體,訊息佇列,訊號量)
目錄 程序間通訊的介紹 管道 匿名管道 原理: 程式碼實現 匿名管道特性 實現管道符 | 命名管道 命名管道特性 程式碼實現 管道讀寫規則 作業系統中ipc的相關命令 共享記憶體(重點) 生命週期: 程式碼實現 程式碼實現獲
Linux中程序間通訊機制----訊息佇列
一、什麼是訊息 訊息(message)是一個格式化的可變長的資訊單元。訊息機制允許由一個程序給其它任意的程序傳送一個訊息。當一個程序收到多個訊息時,可將它們排成一個訊息佇列。 1、訊息機制的資料結構 (1)訊息首部 記錄一些與訊息有關的資訊,如訊息的型別、大小、
程序間通訊的方式——訊號、管道、訊息佇列、共享記憶體
多程序: 首先,先來講一下fork之後,發生了什麼事情。 由fork建立的新程序被稱為子程序(child process)。該函式被呼叫一次,但返回兩次。兩次返回的區別是子程序的返回值是0,而父程序的返回值則是新程序(子程序)的程序 id。將子程序id返回給父程序的理由是
嵌入式Linux併發程式設計,程序間通訊方式,System V IPC,訊息佇列,開啟/建立msgget(), 傳送訊息msgsnd(),格式,接收訊息msgrcv(),控制訊息佇列 msgctl()
文章目錄 1,訊息佇列 2,訊息佇列結構 3,訊息佇列使用步驟 3.1,開啟/建立訊息佇列 msgget() 3.1.1,開啟/建立訊息佇列---示例msgget() 3.2,向訊息佇列傳送訊息 msgs