Ⅰ 總結:linux進程間通信的幾種機制的比較及適
1 管道(Pipe)及有名管道(namedpipe):
管道可用於具有親緣關系進程間的通信,有名管道克服了管道沒有名字的限制,因此,除具有管道所具有的功能外,它還允許無親緣關系進程間的通信;
2 信號(Signal):
信號是比較復雜的通信方式,用於通知接受進程有某種事件發生,除了用於進程間通信外,進程還可以發送信號給進程本身;linux除了支持Unix早期信號語義函數sigal外,還支持語義符合Posix.1標準的信號函數sigaction(實際上,該函數是基於BSD的,BSD為了實現可靠信號機制,又能夠統一對外介面,用sigaction函數重新實現了signal函數);
3 報文(Message)隊列(消息隊列):
消息隊列是消息的鏈接表,包括Posix消息隊列systemV消息隊列。有足夠許可權的進程可以向隊列中添加消息,被賦予讀許可權的進程則可以讀走隊列中的消息。消息隊列克服了信號承載信息量少,管道只能承載無格式位元組流以及緩沖區大小受限等缺點。
4 共享內存:
使得多個進程可以訪問同一塊內存空間,是最快的可用IPC形式。是針對其他通信機制運行效率較低而設計的。往往與其它通信機制,如信號量結合使用,來達到進程間的同步及互斥。
5 信號量(semaphore):
主要作為進程間以及同一進程不同線程之間的同步手段。
6 套介面(Socket):
更為一般的進程間通信機制,可用於不同機器之間的進程間通信。起初是由Unix系統的BSD分支開發出來的,但現在一般可以移植到其它類Unix系統上:Linux和SystemV的變種都支持套接字。
Ⅱ linux 管道原理
Linux原理的學習,我打算由淺入深,從上之下,也就是先了解個大概再逐個深入。先了解一下Linux的進程先。
一、Linux進程上下文
Linux進程上下文,我理解就是進程組成元素的集合。包括進程描述符tast_struct,正文段,數據段,棧,寄存器內容,頁表等。
1)tast_struct
它是一種數據結構,存儲著進程的描述信息,例如pid,uid,狀態,信號項,打開文件表等。是進程管理和調度的重要依據。
2)用戶棧和核心棧
顧名思義,用戶棧是進程運行在用戶態使用的棧,含有用戶態執行時候函數調用的參數,局部變數等;核心棧是該進程運行在核心態下用的棧,保存調用系統函數所用的參數和調用序列。這兩個棧的指針都保存在tast_struct結構中。
3)寄存器
保存程序計數器,狀態字,通用寄存器,棧指針。
4)頁表
線性地址到物理地址的映射
5)正文段,數據段。
二、Linux進程的狀態
Linux中進程共有5個狀態:就緒,可中斷睡眠,不可中斷睡眠,暫停,僵死。也就是說,linux不區分就緒和運行,它們統一叫做就緒態。進程所處的狀態記錄在tast_struct中。
三、進程的控制
1)進程樹的形成
計算機啟動後,BIOS從磁碟引導扇區載入系統引導程序,它將Linux系統裝入內存,並跳到內核處執行,Linux內核就執行初始化工作:初始化硬體、初始化內部數據結構、建立進程0。進程0創建進程1,進程1是以後所有創建的進程的祖先,它負責初始化所有的用戶進程。進程1創建shell進程,shell進程顯示提示符,等待命令的輸入。
2)進程的創建
任何一個用戶進程的創建都是由現有的一個進程完成的,進程的創建要經過fork和exec兩個過程。Fork是為新進程分配相應的數據結構,並將父進程的相應上下文信息復制過來。Exec是將可執行文件的正文和數據轉入內存覆蓋它原來的(從父進程復制過來的),並開始執行正文段。
3)進程的終止
系統調用exit()就可自我終結,exit釋放除了tast_struct以外的所有上下文,父進程收到子進程終結的消息後,釋放子進程的tast_struct。
4)進程的調度
進程的調度是由schele()完成的,一種情況是,當處理機從核心態向用戶態轉換之前,它會檢查調度標志是否為1,如果是1,則運行schele(),執行進程的調度。另一種情況是進程自動放棄處理機,時候進行進程調度。
進程的調度過程分為兩步,首先利用相關策略選擇要執行的進程,然後進行上下文的切換。
四、進程的通信
進程的通信策略主要有,消息,管道,消息隊列,共享存儲區和信號量。
1)信息
消息機制主要是用來傳遞進程間的軟中斷信號,通知對方發生了非同步事件。發送進程將信號(約定好的符號)發送到目標進程的tast_struct中的信號項,接收進程看到有消息後就調用相應的處理程序,注意,處理程序必須到進程執行時候才能執行,不能立即響應。
2)管道
我理解就是兩個進程使用告訴緩沖區中的一個隊列(每兩個進程一個),發送進程將數據發送到管道入口,接收進程從管道出口讀數據。
3) 消息隊列
消息隊列是操作系統維護的一個個消息鏈表,發送進程根據消息標識符將消息添加到制定隊列中,接收進程從中讀取消息。
4)共享存儲區
在內存中開辟一個區域,是個進程共享的,也就是說進程可以把它附加到自己的地址空間中,對此區域中的數據進行操作。
5)信號量
控制進程的同步。
Ⅲ linux系統自帶的消息隊列和rabbitmq有什麼區別
RabbitMQ是使用Erlang編寫的一個開源的消息隊列,本身支持很多的協議:AMQP,XMPP, SMTP, STOMP,也正因如此,它非常重量級,更適合於企業級的開發。同時實現了Broker構架,這意味著消息在發送給客戶端時先在中心隊列排隊。對路由,負載均衡或者數據持久化都有很好的支持。
Ⅳ 請教一個關於linux消息隊列的問題
一般使用步驟:
1. 用ftok產生一個key。
2. 調用msgget(使用key作為參數)產生一個隊列
3. 進程可以用msgsnd發送消息到這個隊列,相應的別的進程用msgrcv讀取。
這里需要注意msgsnd可能會失敗的兩個情況:
a) 可能被中斷打斷(包括msgsnd和msgrcv). 尤其是大流量應用中更容易出現. 比較安全的用法是判斷操作是否被中斷打斷,如果被打斷, 則需要繼續嘗試。
b) 消息隊列滿。產生這個錯誤,則需要考慮提高系統消息隊列規格,或者查看消息接收處是否有問題
4. msgctl函數可以用來刪除消息隊列
消息隊列產生之後,除非明確的刪除(可以用),產生的隊列會一直保留在系統中。linux下消息隊列的個數是有限的,注意不要泄露。如果 使用已經達到上限,msgget調用會失敗,產生的錯誤碼對應的提示信息為no space left on device.
注意點:
1.消息的類型 mtype 不需為非0值。如果使用0,則msgsnd會失敗,並得到」Invalid argument「錯誤。
2.msgflg為0表示阻塞等待,如果msgflg為IPC_NOWAIT表示非阻塞。
3.最好使用root許可權執行消息隊列,否則msgrcv 提示 "Permission denied"。
Ⅳ 請教一個關於linux進程通信消息隊列mq
在Linux中使用消息隊列
Linux提供了一系列消息隊列的函數介面來讓我們方便地使用它來實現進程間的通信。它的用法與其他兩個System V PIC機制,即信號量和共享內存相似。
1、msgget函數
該函數用來創建和訪問一個消息隊列。它的原型為:
int msgget(key_t, key, int msgflg);
與其他的IPC機制一樣,程序必須提供一個鍵來命名某個特定的消息隊列。msgflg是一個許可權標志,表示消息隊列的訪問許可權,它與文件的訪問許可權一樣。msgflg可以與IPC_CREAT做或操作,表示當key所命名的消息隊列不存在時創建一個消息隊列,如果key所命名的消息隊列存在時,IPC_CREAT標志會被忽略,而只返回一個標識符。
它返回一個以key命名的消息隊列的標識符(非零整數),失敗時返回-1.
msgsnd函數
該函數用來把消息添加到消息隊列中。它的原型為:
int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);
msgid是由msgget函數返回的消息隊列標識符。
msg_ptr是一個指向准備發送消息的指針,但是消息的數據結構卻有一定的要求,指針msg_ptr所指向的消息結構一定要是以一個長整型成員變數開始的結構體,接收函數將用這個成員來確定消息的類型。所以消息結構要定義成這樣:
struct my_message{
long int message_type;
/* The data you wish to transfer*/
};
msg_sz是msg_ptr指向的消息的長度,注意是消息的長度,而不是整個結構體的長度,也就是說msg_sz是不包括長整型消息類型成員變數的長度。
msgflg用於控制當前消息隊列滿或隊列消息到達系統范圍的限制時將要發生的事情。
如果調用成功,消息數據的一分副本將被放到消息隊列中,並返回0,失敗時返回-1.
Ⅵ Linux消息隊列
int msgsnd(int msqid,struct msgbuf * msgp,sizet msgsz, int msgflg);
消息類型int型
Ⅶ linux進程間通信(消息隊列)
在與此進程P1通信的進程P2中,同樣的以ftok創建KEY, msgget在該KEY上創建消息隊列,
只需要保證,ftok的參數中,第一個參數,即文件,是同一個文件即可。當P2中的文件與P1不同時,msgget函數將會返回錯誤。
可以說,消息隊列也是通過文件實現的,就像創建一個socket,要使用它時,也已經為其綁定了一個文件fd。
有一個例子不錯,你可以看看。實驗時,需要把ftok的第一個參數,即文件,設置為一個你當前目錄存在的文件。你可以touch一個臨時文件來實驗。
http://blog.csdn.net/lcrystal623/archive/2007/03/16/1531183.aspx
同時,謝謝link的博主。
Ⅷ linux系統編程中的消息隊列該怎麼使用呀
消息隊列用於進程間通信,每個進程可以,只要該消息queueID隊列
的#ifndef CMSGOP_H
#定義CMSGOP_H
#包括類型。 H>
#包括ipc.h>
#包括msg.h>中
類CMsgOp
{
公眾:
CMsgOp ();
虛擬CMsgOp();
typedef結構_customMessageFormat {
整數PROCESSID;
整數CMD;
整數commandArg;
} CCustomMessageFormat; BR p>詮釋的init();
整數發送(常量CCustomMessageFormat&消息);
整數接收(CCustomMessageFormat&消息);
私人:
整數msgQueueID;
結構msgbuf sendBuf;
結構msgbuf recvBuf;
};
#ENDIF / / CMSGOP_H
的#include「 cmsgop.h「
#包括中
#包括中
#包括中
CMsgOp :: CMsgOp()
> {
}
CMsgOp ::CMsgOp()
{
了msgctl(msgQueueID,IPC_RMID,NULL);
}
BR />整型CMsgOp :: init()中
的key_t的key = ftok的(「/ home/maemo/tmp2」,1);
如果(-1 ==鍵) {
PERROR(「ftok的失敗!」);
返回-1;
}
整數RET = msgget(鍵,IPC_CREAT);
>如果(-1 == RET)
{
PERROR(「創建消息隊列失敗!」);
返回-1;
}
msgQueueID = RET;
返回0;
}
整數CMsgOp ::發送(常量CCustomMessageFormat&消息)
{的memcpy(sendBuf.mtext,及訊息,大小(CCustomMessageFormat));
sendBuf.mtype = 1;
整數RET =的msgsnd(msgQueueID,&sendBuf,大小(CCustomMessageFormat),0);
如果(-1 = = RET)
{
PERROR(「消息發送失敗!」);
返回RET;
}
}
整數CMsgOp: :接收(CCustomMessageFormat&消息)
{
整數RET =的msgrcv(msgQueueID,與recvBuf,大小(CCustomMessageFormat),0,IPC_NOWAIT);
如果( - 1 == RET) {
PERROR(「接收消息失敗!」);
返回-1;
}
的memcpy(&消息,recvBuf.mtext,大小(CCustomMessageFormat ));
返回RET;
}
Ⅸ linux 消息隊列
這個編程,主要是看你的消息隊列的指針如何處理了,和類型沒有太大的關系。直接處理指針就行了。
Ⅹ Linux多線程同步之消息隊列有何特點
消息隊列是消息的鏈表,存放在內核中並有消息隊列標示符標示。
msgget用於創建一個新隊列或打開一個現存的隊列。msgsnd將新消息加入到消息隊列中;每個
消息包括一個long型的type;和消息緩存;msgrcv用於從隊列中取出消息;取消息很智能,不一定先進先出
①msgget,創建一個新隊列或打開一個現有隊列
#include
int msgget ( key_t key, int flag );
//成功返回消息隊列ID;錯誤返回-1
②msgsnd: 發送消息
#include
int msgsnd( int msgid, const void* ptr, size_t nbytes, int flag )
//成功返回0,錯誤返回-1
a:
flag可以指定為IPC_NOWAIT;
若消息隊列已滿,則msgsnd立即出錯返回EABAIN;
若沒指定IPC_NOWAIT; msgsnd會阻塞,直到消息隊列有空間為止
③msgrcv: 讀取消息:
ssize_t msgrcv( int msgid, void* ptr, size_t nbytes, long type, int flag );
a. type == 0; 返回消息隊列中第一個消息,先進先出
b. type > 0
返回消息隊列中類型為tpye的第一個消息
c. type < 0
返回消息隊列中類型 <=
|type| 的數據;若這種消息有若干個,則取類型值最小的消息
消息隊列創建步驟:
#define
MSG_FILE "."
struct msgtype {
long mtype;
char buffer[BUFFER+1];
};
if((key=ftok(MSG_FILE,'a'))==-1)
{
fprintf(stderr,"Creat Key Error:%s\n", strerror(errno));
exit
(1);
}
if((msgid=msgget(key, IPC_CREAT | 0666/*PERM*/))==-1)
{
fprintf(stderr,"Creat Message
Error:%s\n", strerror(errno));
exit
(1);
}