linux进程通信发送方式,Linux服务器编程——Linux系统编程之进程通信
進程通信又稱IPC
IPC方法
方法:管道(最簡單)
信號(開銷最小)
共享映射區/共享內存(無血緣關系)
本地套接字(最穩定)
Linux文件類型: -?? 文件
d? 目錄
l?? 符號鏈接
s?? 套接字??????? 偽文件
b??? 塊設備? ? ?? 偽文件
c字符設備?????? 偽文件
p管道?????????????? 偽文件
管道
其本質是:
1、偽文件,實質為內核緩沖區
2、由兩個文件描述符表示,一個表示讀端,一個表示寫端
3、數據從讀端流入,從寫端流出
管道原理:內核使用環形隊列機制,借助內和緩沖區實現
管道局限性:1、數據自己讀不能自己寫
2、數據一旦被讀走,便在管道中不存在,不可反復讀取
3、由于管道采用半雙工通信方式,數據只能在一個方向上流動
4、只有公共祖先的進程間才能使用管道
匿名管道
適用于:只有公共祖先的進程
pipe函數
作用:創建管道
頭文件
函數模型
#include int pipe(int pipefd[2])
pipefd[2]:傳出參數
讀端、寫端由自己決定
返回值:0 成功
非0 錯誤代碼
管道讀寫規則:
讀管道:當管道中有數據,read返回實際讀到的字節數
當管道中沒有數據,若寫端全關閉,read函數返回0
若任有寫端打開,阻塞等待
寫管道:當讀端全關閉時,進程異常終止(SIGPIPE信號)
有讀端打開,若管道未滿,寫數據,返回寫入字節數
若管道已滿,阻塞(少見)
獲取管道緩沖區大小:命令 ulimit -a
fpathconf函數
作用:獲取管道緩沖區大小
頭文件
#include 函數原型
long int fpathconf(int fd,int parameter)
paramter:__PC_PIPE_BUF
#define _GNU_SOURCE
#include #include int pipe2(int pipefd[2], int flags)
優點:實現手段簡單
缺點:單向通信,只有血緣關系進程間使用
有名管道
命名管道是一種特殊類型的文件。
命名管道和匿名管道區別:
管道應用的一個限制就是只能在具有親緣關系的進程間通信,命名管道可以再不相關的進程間交換數據。
mkfifo函數
作用:創建一個FIFO文件
頭文件
#include 函數原型
int mkfifo(const char *filename, mode_t mode)
mode:權限
返回值:成功 0
-1 失敗
可多讀端,多寫端
共享內存
命名映射區
mmap函數
作用:
頭文件:
#include 函數原型
void* mmap(void *addr, int length , int port , int flag, int fd, off_t offset)
參數:
addr:建立的映射區的首地址,由Linux內核指定,直接傳NULL
length:創建映射區的大小
port:映射區的權限
PORT_READ
PROT_WRITE
PROT_READ| PROT_WRITE
flags:標志為參數(常用于設定更新物理區域,設置共享,創建匿名映射區)
MAP_SHARED:會將內存所做的修改反映到硬盤
MAP_PRIVATE
fd:文件描述符
offset:映射文件的便宜為4K倍數
返回值:成功 返回映射區首地址
失敗 MAP_FAILD 宏
munmap函數
頭文件
#include 函數原型
int munmap(void* addr, size_t length)
使用注意事項:
1、創建映射區過程中,隱含一次對文件的讀操作
2、當MAP_SHARED,要求映射區的權限<= 文件打開權限。而MAP_PRIVATE則無所謂,因為mmap中的權限是對內存的限制
3、映射區的釋放與文件關閉無關,只要映射建立成功,文件可以立即關閉。
4、當映射文件大小為0時,不能創建映射區。
5、munmap傳入的地址一定是mmap的返回地址。堅決抵制自增操作
6、文件偏移量必須是4096的倍數
7、mmap創建映射區出錯率非常高,一定要檢查返回值,確保映射區建立成功后在操作
匿名映射區
映射區的缺陷是,每次都創建映射區時一定要依賴一個文件才能實現,通常要open,unlink,close等比較麻煩,因此可以利用匿名映射來代替。
int *p = mmap(NULL, 4, PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0)
mmap無血緣關系進程間通信
信號
基本的屬性
1、簡單
2、不能攜帶大量信息
3、滿足某個特定條件才發送
與信號相關的事件和狀態
產生信號:
按鍵產生
系統調用?? kill??? raise?? abort
軟件條件??? 定時器? alarm
命令條件?? kill命令
遞答:遞送且到達
未決:產生和遞答之間狀態
信號處理方式:
1、執行默認動作
2、忽略(丟棄)
3、捕捉(由用戶處理函數)
信號4要素
1、編號????? 2、名稱????? 3、時間??????? 4、默認處理動作
查看man 7 signal可以查看幫助
產生信號函數
kill函數/命令
kill命令:kill -SIGKILL pid
頭文件
#include #include 函數原型
int kill(pid_t pid, int sig)
參數:
pid:>0 發送信號給指定進程
=0 發送信號給 調用kill函數進程屬于同一進程組的所有進程
<0 取pid的絕對值發給對應進程
=-1 發給進程 有權限發送的系統中所有進程
raise函數
作用:給當前進程發送信號
頭文件
#include #include 函數模型
int raise(int sig)
abort函數
作用:給當前進程發送 異常終止信號 SIGABRT
頭文件
#include #include
函數原型
int abort(void)
軟件條件產生信號
alarm函數
每個進程有且只有唯一一個定時器
頭文件:
#include 函數原型
unsigned int alarm(unsigned int seconds)
返回值:
返回0或剩余的秒數,通常alarm(0)返回鬧鐘剩余秒數,無失敗,支持秒級,與進程狀態無關
setitimer函數
作用:設置定時器,精度us級
頭文件
#include 函數原型
int getitimer(int which, struct itimerval *curr_value)
int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value)
參數:
which:制定定時方式
自然定時 ITIMER_REAL SIGALRM 計算自然時間
虛擬空間計時(用戶空間) ITIMER_VIRTUAL SIGVTALRM 只計算進程占用CPU時間
運行時間計時(用戶+內核) ITIMER_PROF ITIMER_PROF 計算占用CPU及執行系統調用的時間
struct itimerval{
struct timeval it_interval; //下一次定時 ,,兩次任務間隔
struct timeval it_value; //當前定時值,用來定時時長
};
struct timeval{
time_t tv_sec; //秒數
suseconds_t tv_usec; //微秒數
};
信號集操作函數
信號集設定
sigset_t set; //無符號長整形 typedef unsigned long sigset_t
int sigemptyset(sigset_t *set); 將某個信號請0
int sigfillset(sigset_t *set) 將某個信號集置1
int sigaddset(sigset* set, int signum) 將某個信號加入信號集
int sigdelset(sigset* set, int signum) 將某個信號清除信號集
int sigismember(const sigset_t* set, int signum) 判斷某個信號在信號集中
sigprocmask函數
作用:屏蔽信號,解除信號,本質讀取或修改進程的信號屏蔽字,嚴格注意:屏蔽信號:只是將信號處理延后執行,而忽略表示將信號丟棄
頭文件
函數原型
int sigprocmask(int how, const sigset_t * set, sigset_t *oldset)
參數;set 傳入參數,位圖,1表示屏蔽
oldset? 傳出參數 用來保存舊的信號屏蔽集
how:假設當前信號屏蔽字mask
SIG_BLOCK,set表示需要屏蔽的信號
SIG_BLOCK,set表示需要解除的屏蔽信號
SIG_SETMASK,代替原始屏蔽的新的屏蔽
sigpending函數
作用:讀取當前進程的未決信號集
函數原型
int sigpending(sigset_t *set)
參數:set 傳出參數
信號捕捉
signal函數
頭文件
#include 函數原型
typedef void (*sighandler_t)(int)
sighandler_t signal(int signum, sighandler_t handler)
返回值:SIG_ERR 錯誤
sigaction函數
頭文件
#include 函數原型
int sigaction(int signum, const struct sigaction * act, struct sigaction *oldact)
作用:修改信號處理動作
參數
struct sigaction{
void (*sa_handler)(int) //函數名
void (*sa_sigaction)(int, siginfo_t *, void *) //當sg_flags被指定為SA_SIGINFO時,使用該型號處理程序(很少使用)
sigset_t sa_mask //用于 處理函數在被調用時屏蔽生效
int sa_flags //0表示默認屬性
void (*sa_restorer)(void) //廢棄,已不用
};
信號捕捉特性
1、阻塞的信號不支持排隊,產生多次,只記錄一次。
競態條件
pause函數
作用:調用該函數可以使進程主動掛起,等待信號喚醒
頭文件
#include 函數原型
int pause(void)
返回值:
1、如果信號的默認處理動作是終止進程,則進程終止,pause函數沒有機會返回
2、如果信號的默認處理是忽略,進程繼續掛起,pause函數不返回
3、如果信號的處理動作是捕捉,則調用完信號處理函數之后,pause函數返回-1
4、pause收到的信號不能被屏蔽,如果被屏蔽就不能喚醒
信號傳參
發送信號傳參
sigqueue函數對應kill函數,但可想指定進程發送信號的同時攜帶參數。
sigqueue函數
頭文件
函數原型
int sigqueue(pid_t pid, int sig, cinst union sigval value);
union sigval{
int sigval_int;
void *sival_ptr;
};
捕捉函數傳參
sigaction函數
見信號捕捉函數
當注冊信號捕捉函數,不適用sa_handler 而使用 sa_sigaction.
進程組
進程組操作函數
getpgrp函數
獲得當前進程組ID
pid_t getpgrp(void)
getpgid函數
獲取指定進程的進程組ID
pid_t getpgid(pid_t pid)
setpgid函數
改變進程默認的所屬進程組,通常加入一個現有進程組或創建型進程組
int setpgid(pid_t pid, pid_t pgid)
會話
創建會話
創建會話有6點:
1、調用進程不能是進程組租場,新進程變為會長
2、該進程變為新進程組組長
3、需要root權限(Ubuntu不需要)
4、新會話丟棄原有控制終端,該回話沒有控制終端
5、該調用進程是組長進程
6、建立會話時,先調用fork,父進程種子,子進程調用setpgid
getsid函數
獲得進程的會話ID
pid_t getsid(pid_t pid)
srtsid函數
int setsid()
守護進程
守護進程/精靈進程:Linux后臺服務進程,無終端,周期性執行某種任務或等待處理某些發生的條件。
創建守護進程,最關鍵的是調用setsid函數創建一個新的session,并且成為session leader
創建守護者模型
1、創建子進程,父進程退出,所有工作都脫離了控制終端
2、在子進程中創建新的會話
setsid函數
3、改變當前目錄為根目錄?? chdir函數
防止占用可卸載的文件系統,也可以換成其他路徑
4、重設文件權限掩碼
umask函數
防止繼承的文件創建屏蔽字拒絕某些權限,增加靈活性
5、關閉文件描述符
繼承的打開文件不會用到,浪費資源,不關閉 0,1,2?? 而是重定向? >? /dev/null????????????????????? dup2()
6、開始執行守護進程核心
7、守護進程退出處理
總結
以上是生活随笔為你收集整理的linux进程通信发送方式,Linux服务器编程——Linux系统编程之进程通信的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MySQL客户端工具的选择
- 下一篇: linux分区转换gpt命令,Linux