進 程 間 通 信
進程間通信:三大類
1、古老的通信方式
無名管道
有名管道
信號 ====》唯一的異步通信方式
2、systemV IPC 對象
消息隊列
共享內存 ===》效率最高的通信方式
信號量集
3、BSD socket 套接字
域內套接字 ==》單機進程間通信
網絡套接字 ==》不同主機上的進程間通信
古老的通信方式:
1、管道 ==》無名管道 有名管道
無名管道 ==》pipe
1、特性
只能用於具有親緣關係的進程間使用。
半雙工的通信模式,有固定的讀寫端。
屬於特殊的設備文件,只能用文件IO讀寫。
該類型的文件不支持定位操作。
2、使用流程
創建管道===》打開管道 ===》讀寫管道 ==》關閉管道
pipe() read()/write() close()
頭文件: #include <unistd.h>
原型: int pipe(int fd[2]);
功能:該函數可以創建一個無名管道,
並且自動打開該管道。
參數: fd[2] 管道的讀寫端,有如下默認約定
fd[0] 固定的讀端
fg[1] 固定的寫端
返回值:成功 0
失敗 -1;
讀: read
寫: write()
關閉: close()
有名管道 ===>fifo ===>在無名管道基礎之上增加了一個文件名稱
方便在不同進程間使用。
操作流程:
創建有名管道 ===》打開管道 ===》讀寫管道 ==》關閉管道 ===》卸載管道。
mkfifo open read/write close unlink
1、創建有名管道 ==》mkfifo
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
功能:在指定的pathname路徑下創建一個權限爲mode的有名管道。
參數:pathname 要創建的有名管道的路徑+管道名稱
mode 要創建的管道文件權限。
返回值:成功 0
失敗 -1;
***** 注意:
所有的管道都是設備文件,同時該設備文件有固定的讀寫端。
open();的參數2 不能是 O_RDWR,只能是O_RDONLY 或者 O_WRONLY 之一
#include <unistd.h>
int unlink(const char *pathname);
功能:通過該函數可以完成指定的有名管道卸載。文件會被刪除。
參數:pathname 要卸載的管道
返回值:成功 0
失敗 -1;
注意:unlink函數一般用於最後管道沒有人使用的時候卸載用。
一般爲了有名管道的配合使用。管道的創建工作可以獨立執行
或者在讀端啓動的時候首先創建。
練習:
1、從a.out程序中讀取指定文件內容通過有名管道發送到b.out
並從 b.out 中打印輸出。
2、測試有名管道能否在fork之後的父子進程間使用。
注意:一般在項目中需要有一個有名管道的維護工具,
可以動態的手工創建並刪除管道.比如:
fifo_tool 名稱
功能: fifo_tool -A abc ===>在當前路徑下新建一個名稱爲
abc 的有名管道
fifo_tool -D abc ===》刪除當前路徑下名稱爲abc的管道。
信號通信:====》傳遞的是信號 ,而不是數據.
通信框架: 發送端進程 ===》信號 ===》接收端進程
1、發送端進程 ===》函數: kill() raise() alarm () pause()
#include <sys/types.h>
#include <signal.h>
原型:int kill(pid_t pid, int sig);
功能: 通過該函數可以給指定的pid進程發送sig編號的信號。
參數: pid 要接受信號的進程pid號
sig 要接受的信號。
返回值:成功 0
失敗 -1;
原型: int raise(int sig);
功能: 進程自身給自己發送一個sig信號。
參數: sig 發給自己的信號編號
返回值:成功 0
失敗 -1;
頭文件 #include <unistd.h>
原型: unsigned int alarm(unsigned int seconds);
功能:定時由OS給當前進程發送一個定時信號SIGALRM
默認該信號會殺死進程。
參數:seconds 程序從當前函數開始後seconds秒後會
收到來自OS的SIGALRM信號。
返回值:成功 0
失敗 -1;
原型:int pause(void);
功能:使當前運行的進程暫停。
返回值:成功 0
失敗 -1;
2、信號 ===》kill -l 中前32個不穩定信號。
3、接受端進程 ===》進程收到信號的處理過程:
每個進程對信號有三種處理方式:
1、默認處理
2、忽略處理
3、自定義處理
信號的註冊函數: ==》signal 函數
原型:
void (*signal(int signum,void (*handler)(int)))(int);
===>void (*xxx)(int aa);===>函數指針
xxx == signal(int signum,void(*handler)(int));
===>typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
signal(int signum,fun); ===>信號註冊函數
其中:signum 表示要處理的信號編號
fun 表示信號的處理方式:
如果fun == SIG_IGN ===>表示忽略處理方式
SIG_DFL ===>表示默認處理方式
函數地址 ===》自定義函數‘
重要:在所有的信號中9 號的SIGKILL 和 19 號的 SIGSTOP
信號不能被忽略。同時也不能被修改。
特殊:10 SIGUSR1
12 SIGUSR2
以上兩個信號在所有32個信號中是唯一的兩個沒有具體
含義的臨時信號,預留給程序員編程使用。
練習題:
編寫信號處理程序,當收到10號和12號信號的時候啓動不同的程序。
其他信號都按默認處理流程。