程序間通信
基本概念:
什麼是程序間通信:
是指兩個或多個程序之間互動資料的過程,是因為程序之間是互相獨立的,為了協同工作的需要必須要互動資料
程序間通信的分類:
簡單的程序間通信:信号、檔案、環境變量、指令行參數
傳統的程序間通信:管道檔案
XSI程序間通信: 共享記憶體、消息隊列、信号量
網絡程序間通信: 套接字Socket
傳統程序間通信-管道(FIFO):
管道是UNIX系統中最古老的程序間通信方式,古老意味着所有系統都支援,早期的管道檔案都是半雙工,現有的一些系統的管道是全雙工的
管道是一種特殊的檔案,它的資料在檔案中是流動的,讀取之後就會消失,如果檔案中沒有任何資料讀取時會阻塞
有名管道:基于有檔案名的管道檔案的通信
程式設計模型:
程序A 程序B
建立管道
打開管道 打開管道
寫資料 讀資料
關閉管道 關閉管道
删除管道
建立管道檔案:
1、mkfifo filename
2、函數
int mkfifo(const char *pathname, mode_t mode);
功能:建立有名管道檔案
pathname:管道檔案路徑
mode:管道檔案權限
匿名管道:
注意:匿名管道隻适合通過fork建立的父子程序之間使用
int pipe(int pipefd[2]);
功能:建立一個匿名管道檔案,傳回管道檔案的讀權限fd和寫權限fd
pipefd:傳回用于存儲管道檔案讀寫fd的數組,輸出型參數
pipefd[0] 用于讀
pipefd[1] 用于寫
程式設計模型:
父程序 子程序
擷取一對fd 共享了一對fd
關閉讀 關閉寫
寫資料 讀資料
關閉寫 關閉讀
XSI程序間通信:
X/Open公司制定用于程序間通信的系統接口
XSI程序間通信技術都需要借助系統核心,需要建立核心對象,核心對象會以整數形式傳回給使用者态,相當于檔案描述符,也叫做IPC辨別符
檔案的建立打開需要借助檔案名,同樣的,IPC核心對象建立需要借助IPC鍵值(整數),必須要確定IPC鍵值是獨一無二的
key_t ftok(const char *pathname, int proj_id);
功能:計算出一個獨一無二的IPC鍵值
pathname:項目路徑,不是依靠字元串計算,而是依靠路徑的位置以及項目編号計算的,是以不能提供假路徑,否則可能會産生同樣的IPC鍵值
proj_id:項目編号
傳回值:計算出來的IPC鍵值
共享記憶體:
基本特點:
兩個或者多個程序之間共享一塊由核心負責維護的記憶體,該記憶體可以與多個程序的虛拟記憶體進行映射
優點:不需要複制資訊,是一種最快的IPC通信機制
缺點:需要考慮同步通路的問題,一般借助信号來解決
int shmget(key_t key, size_t size, int shmflg);
功能:建立/擷取共享記憶體
key:由程序提供的一個獨一無二的IPC鍵值
size:共享記憶體的大小,擷取時該參數無意義,一般給0
shmflg:
IPC_CREAT 建立共享記憶體
IPC_EXCL 共享記憶體如果已存在,則傳回錯誤
擷取時直接給0
mode_flags 建立共享記憶體時需要提供權限 IPC_CREAT|0644
傳回值:IPC辨別符,錯誤時傳回-1
void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:讓虛拟記憶體與共享記憶體進行映射
shmid:IPC辨別符
shmaddr:想要映射的虛拟記憶體首位址,為NULL時系統會自動操作
shmflg:
SHM_RDONLY:以隻讀方式映射共享記憶體
SHM_RND:隻有當shmaddr參數不為NULL時有效,表示對shmaddr參數向下取記憶體頁的整數倍,作為映射位址
如果都不需要,則寫0
傳回值:與共享記憶體映射後的虛拟記憶體的首位址,失敗傳回(void *) -1 或者 0xFFFFFFFF
int shmdt(const void *shmaddr);
功能:取消映射
shmaddr:映射過的虛拟記憶體首位址
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:删除/控制共享記憶體
shmid:IPC辨別符
cmd:
IPC_STAT 擷取共享記憶體的屬性 則buf為輸出型參數
IPC_SET 設定共享記憶體的屬性 則buf為輸入型參數
IPC_RMID 删除共享記憶體 則buf給NULL
buf:
struct shmid_ds {
struct ipc_perm shm_perm; //所有者的相關資訊
size_t shm_segsz; //共享記憶體的位元組數
time_t shm_atime; //最後映射的時間
time_t shm_dtime; //最後取消映射的時間
time_t shm_ctime; //最後改變的時間
pid_t shm_cpid; //建立者的程序号
pid_t shm_lpid; //最後映射、取消映射者的程序号
shmatt_t shm_nattch; //目前映射的次數
...
};
struct ipc_perm {
key_t __key; //建立共享記憶體的IPC鍵值
uid_t uid; //目前使用共享記憶體的使用者ID
gid_t gid; //目前使用共享記憶體的組ID
uid_t cuid; //建立共享記憶體的使用者ID
gid_t cgid; //建立共享記憶體的使用者組ID
unsigned short mode; //共享記憶體的權限
unsigned short __seq; //共享記憶體的序列号
};
程式設計模型:
程序A 程序B
建立共享記憶體 擷取共享記憶體
映射共享記憶體 映射共享記憶體
寫資料并通知其他程序 接收到通知後讀資料
接收到通知後讀資料 寫資料并通知其他程序
取消映射 取消映射
删除共享記憶體
消息隊列:
基本特點:
由核心維護管理的資料連結清單,是通過消息類型收發資料
int msgget(key_t key, int msgflg);
功能:建立\擷取消息隊列
key:IPC鍵值
msgflg:
IPC_CREAT 建立消息隊列
IPC_EXCL 如果消息隊列已存在則傳回錯誤
mode: 當建立消息隊列時需要提供權限
傳回值:成功傳回IPC辨別符,失敗傳回-1
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
功能:向消息隊列發送資料
msqid:IPC辨別符
msgp:要發送的消息的首位址
struct msgbuf {
long mtype; // 消息類型
char mtext[n]; // 資料
};
msgsz:資料的位元組數,是不包含消息類型的
msgflg:
阻塞一般寫0
IPC_NOWAIT 當消息隊列滿時,不等待立即傳回
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
功能:從消息隊列中讀取資料
msqid:IPC辨別符
msgp:存儲資料結構體首位址
msgsz:資料結構體的位元組數
msgtyp:要讀取的消息類型,是按照類型的值來讀取消息,而不是按照順序
>0 讀取消息隊列中第一條等于msgtyp的消息
=0 讀取消息隊列中的第一條消息
<0 讀取消息類型小于abs(msgtyp)的消息,如果有多個滿足則讀取值最小的
msgflg:
IPC_NOWAIT 消息類型不符合時不阻塞,立即傳回
MSG_EXCEPT 如果msgtyp>0,則讀取第一個消息類型不是msgtyp的消息
MSG_NOERROR 如果不包含此标記,則消息的實際長度>msgsz,則會傳回錯誤,并且讀取失敗,如果包含此标記,則最多讀取msgsz個位元組,確定一定成功
傳回值:成功讀取到的位元組數
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
功能:删除/控制消息隊列
msqid:IPC辨別符
cmd:
IPC_STAT 擷取消息隊列的屬性 則buf為輸出型參數
IPC_SET 設定消息隊列的屬性 則buf為輸入型參數
IPC_RMID 删除消息隊列 則buf給NULL
buf:
struct msqid_ds {
struct ipc_perm msg_perm; // 屬主資訊
time_t msg_stime; // 最後發送時間
time_t msg_rtime; // 最後接收時間
time_t msg_ctime; // 最後修改時間
unsigned long __msg_cbytes; // 目前消息隊列位元組數
msgqnum_t msg_qnum; // 目前的消息數量
msglen_t msg_qbytes; // 消息的最大位元組數
pid_t msg_lspid; // 最後發送者的PID
pid_t msg_lrpid; // 最後接收者的PID
};
程式設計模型:
程序A 程序B
建立消息隊列 擷取消息隊列
發送消息 接收消息
接收消息 發送消息
删除消息隊列