[Linux]消息隊列

我們知道進程間通信的方法有多種,主要有管道,消息隊列,信號量,共享內存,socket等。之前介紹過管道,今天再介紹一個新的概念–消息隊列

消息隊列:將一個進程到另一個進程之間發送數據塊的方式。這些發送的數據塊需要存在一個消息隊列緩沖區中。這些數據塊都是有一定的類型的,我們可以通過存放消息的數據塊來避免命名管道與匿名管道所帶來的同步與阻塞問題。與管道不同的是,消息隊列是基于消息的,而管道是基于字節流的。同時,消息隊列中存放的消息的數量是有限的。有最大長度(MSGMAX)和消息隊列的總的字節數(MSGMNB)。也有系統規定的消息隊列的總數(MSGMNI)。

這里寫圖片描述

內核為每個IPC對象維護了一個數據結構:struct ipc;


struct ipc_perm {
key_t __key; /* ftok所獲取的唯一標識的key值*/
uid_t uid; /* 擁有者的有效uid*/
gid_t gid; /* 擁有者的有效gid */
uid_t cuid; /* 創建者的有效uid*/
gid_t cgid; /* 創建者的有效gid */
unsigned short mode; /* 權限 */
unsigned short __seq; /* 序列號*/

注:

消息隊列,信號量,共享內存都有一個ipc數據結構。

在/usr/include/linux/msg.h下,有一個消息隊列的數據結構:

這里寫圖片描述

由圖可以看到ipc_perm就是剛剛說的幾種通信方式所共有的數據結構。其他的一些就是消息隊列結構體所私有的特性。還有其中的msg_first指針和msg_last指針分別指向消息隊列的第一條消息和最后的消息。消息隊列是用鏈表實現的。

這里寫圖片描述

同樣,這幅圖也是在msg.h中的。這里是消息緩沖區結構體和對于消息的一些信息。msgbuf結構體中的mtype是寫的消息的長度大小,即mtext的size。數組mtext即是存放消息的數組。

消息隊列的具體實現:

1.創建消息隊列:

int msgget(key_t key,int msgflag);

key可以認為是端口號,由ftok生成一個唯一的key值。用來創建消息隊列。

msgflag:是創建的消息隊列的方式,有IPC_CREAT和IPC_EXCL。

(1)IPC_CREAT:單獨使用時,如果已經存在已有的IPC資源,就直接返回已存在的IPC,如果不存在則創建一個新的IPC資源。

(2)IPC_CREAT|IPC_EXCL:同時使用時表示,不存在則創建一個,存在的話返回錯誤消息。

2.將消息發送到消息隊列中

int msgsnd(int msgid,const void* msgp,size_t msgsz,int msgflg);

msgid:表示唯一確定的一個消息隊列的id。

msgp: 表示存放數據的消息緩沖區

msgsz:消息文本的大小

msgflg:表示在隊列沒有數據的情況下進行的操作。一般設置為0,表示當隊列空或滿的時候,以阻塞式等待的方式進行處理。

3.從消息隊列中取消息

ssize_t msgrgv(int msgid,const void* msgp,size_t msgsz,long msgtyp,int msgflg);

和上述往消息隊列中寫數據類似,這里取消息時,有msgtyp表示取哪種類型的消息,即消息隊列中讀取的消息形態。

4.設置消息隊列的屬性

int msgctl(int msgid,int cmd,struct msqid_ds *buf);

這里主要是對destroy進行操作,將cmd設置為IPC_RMID即可。

代碼實現(server端與client端的通信):

//comm.h
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>#define PATHNAME "."
#define PROJ_ID 0x6666
#define SERVER_TYPE 1
#define CLIENT_TYPE 2struct msgbuf {long mtype;char mtext[1024];
};int createMsgqueue();
int getMsg();
int destroyMsg(int msgid);
int recvMsg(int msgid,long recvtype,char out[]);
int sendMsg(int msgid,long who,char* msg);#endif   //_COMM_H//comm.c
#include"comm.h"int commMsgqueue(int flags)
{key_t _key = ftok(PATHNAME,PROJ_ID);if(_key < 0){perror("ftok");return -1;}int msgid = msgget(_key,flags);if(msgid < 0){perror("msgget");return -2;}return msgid;
}int createMsgqueue()
{return commMsgqueue(IPC_CREAT | IPC_EXCL|0666);
}
int getMsg()
{return commMsgqueue(IPC_CREAT);
}
int destroyMsg(int msgid)
{if(msgctl(msgid,IPC_RMID,NULL) < 0){perror("msgctl");return -1;}return 0;
}int recvMsg(int msgid,long 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;
}int sendMsg(int msgid,long 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;
}//server.c
#include"comm.h"
#include<stdio.h>int main()
{int msgid = createMsgqueue();char buf[1024];while(1){buf[0]=0;recvMsg(msgid,CLIENT_TYPE,buf);printf("client# %s\n",buf);printf("please Enter# ");fflush(stdout);ssize_t s = read(0,buf,sizeof(buf));if(s > 0){buf[s-1] = 0;sendMsg(msgid,SERVER_TYPE,buf);printf("send done,wait recv...\n");}}destroyMsg(msgid);return 0;
}//client.c
#include"comm.h"
#include<stdio.h>int main()
{int msgid = createMsgqueue();char buf[1024];while(1){buf[0]=0;recvMsg(msgid,CLIENT_TYPE,buf);printf("client# %s\n",buf);printf("please Enter# ");fflush(stdout);ssize_t s = read(0,buf,sizeof(buf));if(s > 0){buf[s-1] = 0;sendMsg(msgid,SERVER_TYPE,buf);printf("send done,wait recv...\n");}}destroyMsg(msgid);return 0;
}
[xiaoxu@bogon msgqueue]$ cat client.c 
#include<stdio.h>
#include"comm.h"int main()
{int msgid = getMsg();char buf[1024];while(1){buf[0]=0;printf("please Enter# ");fflush(stdout);ssize_t s = read(0,buf,sizeof(buf));if(s > 0){buf[s-1] = 0;sendMsg(msgid,CLIENT_TYPE,buf);printf("send done,wait recv...\n");}recvMsg(msgid,SERVER_TYPE,buf);printf("server# %s\n",buf); 
}return 0;
}
//Makefile
.PHONY:all
all:client serverclient:client.c comm.cgcc -o $@ $^
server:server.c comm.cgcc -o $@ $^.PHONY:clean
clean:rm -f server client

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/382720.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/382720.shtml
英文地址,請注明出處:http://en.pswp.cn/news/382720.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

詳解centos7 YCM YouCompleteMe自動補全安裝,親測成功

文章經重新排版轉移至以下鏈接 https://blog.csdn.net/csdn_kou/article/details/84633663

python 異步與io

文檔地址&#xff1a; https://docs.python.org/zh-cn/3/library/asyncio.html 以后再記錄學習筆記 待續。。。

tornado 學習注意事項--00

設置url匹配的時候&#xff0c; (r/(.*), AMStaticFileHandler,dict(pathos.path.join(current_path, html), default_filenameindex.html))像這種語句要放到最后&#xff0c;因為放到前面的話&#xff0c; 后面的就無法匹配&#xff01;

C++關鍵字速查手冊

[TOC] https://blog.csdn.net/csdn_kou/article/details/81113215 C98關鍵字 C11 關鍵字共73個 alignas alignof用于獲取取指定表達式指定的&#xff08;類似sizeof&#xff0c;可以直接是類型名&#xff09;的對齊(alignment)。alignas用于聲明時指定對齊類似于現有的類型…

[Linux]信號

Linux下的信號是一個什么概念呢。我們在現實生活中也遇到過信號之類的。比如紅綠信號燈&#xff0c;班主任叫你去辦公室并且臉色不好&#xff0c;諸如此類的都會給你一個信號。讓你辨別事情的發生。同樣&#xff0c;Linux下也有許多的信號&#xff0c;讓你執行相應的操作。比如…

怎么用VLC播放器將m3u8鏈接視頻下載到本地

轉載 https://blog.csdn.net/saddyyun/article/details/85245135

【1】C++面試題函數引用重載宏命名空間

函數重載的條件 ? 同一個名字 ? 函數名字相同 ? 參數列表不同 ? 同一個作用域 為什么c支持函數重載而c不支持&#xff1f; c函數名字的修飾規則不一樣。c編譯器對函數修飾規則把int的參數列表形式加了進來&#xff0c;從而保證底層使用不同 cAdd(int a,int b)_AddcA…

[數據結構]Map和Set

說起map和set&#xff0c;想必我們都學過紅黑樹了吧&#xff0c;map和set就是紅黑樹的一個應用領域。它的底層就是由紅黑樹來實現的。下面簡單說一下map和set的使用吧。 首先&#xff0c;有一個栗子是這樣的&#xff0c;讓我們統計出每種水果出現的次數。 我們會想到怎么解決…

js獲取Json對象的長度

有兩種Json形式&#xff1a; 第一種&#xff1a; var json1 {"data":[{"name":"zs","age":"10"}]};對于這種格式的json數據&#xff0c;如果想獲取data的長度&#xff0c;就可以用以下這種方式&#xff1a; var length …

生產者消費者模型(條件變量)

三種關系&#xff1a;互斥&#xff0c;同步&#xff0c;互斥和同步 兩類角色:生產者&#xff0c;消費者&#xff08;線程&#xff09; 一個交易場所&#xff1a;生產者消費者共享的區域 賣蘋果的模型 dish上面只有一個蘋果買家必須要等賣家把蘋果放到dish上才可以去買蘋果。…

linux之信號

信號&#xff1a;在生活中&#xff0c;我們遇到過不同種類的信號&#xff0c;比如&#xff1a;&#xff08;交通信號&#xff0c;乃至某個人的表情&#xff0c;動作等帶給你不同的信號&#xff09;然而&#xff0c;在我們的linux下&#xff0c;我們最熟悉的就是&#xff0c;當遇…

視頻解析有感,在解析 iqiyi與qq視頻的時候,記錄一些發現

最近對iqiyi與qq視頻解析發現&#xff0c;兩個網站的解析流程&#xff0c;尤其是反解析措施 各有特點&#xff0c;簡單記錄一下 先說iqiyi&#xff0c; 瀏覽器模擬移動端可以拿到視頻的mp4鏈接&#xff0c;這個不多說。 iqiyiPC端瀏覽器獲取 ts過程&#xff1a; a.iqiyi一次性…

C語言atoi函數的用法

#include < stdlib.h > int atoi(const char *nptr);用法&#xff1a;將字符串里的數字字符轉化為整形數。返回整形值。 注意&#xff1a;轉化時跳過前面的空格字符&#xff0c;直到遇上數字或正負符號才開始做轉換&#xff0c;而再遇到非數字或字符串結束時(’/0’)才…

[Linux]繼續探究mysleep函數(競態條件)

之前我們探究過mysleep的簡單用法&#xff0c;我們實現的代碼是這樣的&#xff1a; #include<stdio.h> #include<signal.h>void myhandler(int sig) {}unsigned int mysleep(unsigned int timeout) {struct sigaction act,oact;act.sa_handler myhandler;sigempt…

C語言的atoi和C++的to_string

to_stringint to string將其他型轉換成字符串型atoiascii to integer是把字符串轉換成整型數的一個函數 to_string #include <iostream> // std::cout #include <string> // std::string, std::to_stringint main () {std::string perfect std::to_string…

ubuntu 升級python3.5到python3.7,并升級pip3

1, 下載python3.7.tgz 文件&#xff0c;解壓&#xff0c; 2. 編譯安裝 3. 刪除 /usr/bin 目錄下的 pip3, python3 4. 建立新的軟連接&#xff1a; #添加python3的軟鏈接ln -s /usr/local/python3/bin/python3.7 /usr/bin/python3#添加 pip3 的軟鏈接ln -s /usr/local/python3/b…

[Linux]死鎖

死鎖是指多個進程在運行過程中因爭奪資源而造成的一種僵局&#xff0c;當進程處于這種僵持狀態時&#xff0c;若無外力作用&#xff0c;它們都將無法再向前推進。之前信號量的時候我們知道&#xff0c;如果多個進程等待&#xff0c;主要體現在占有鎖的問題上。死鎖也可以被定義…

Python安裝第三方模塊總結 轉載的

轉自 https://www.jellythink.com/archives/541

[C++]vector創建二維數組

c.resize(n);將c重置為大小為n個元素向量&#xff0c;如果n比原來的元素多&#xff0c;則多出的元素常被初始化為0//節選《面向對象的程序設計》杜茂青 int N5, M6; vector<vector<int> > Matrix(N); for(int i 0; i< Matrix.size(); i){ Matrix[i].resize(M…

[Linux]線程安全和可重入函數

線程安全&#xff1a;一個函數被稱為線程安全的&#xff0c;當且僅當被多個并發進程反復調用時&#xff0c;它會一直產生正確的結果。如果一個函數不是線程安全的&#xff0c;我們就說它是線程不安全的。 重入&#xff1a;函數被不同的控制流程調用,有可能在第一次調用還沒返回…