在Linux世界里,進(jìn)程并非孤立存在。無論是后臺服務(wù)協(xié)作(如Web服務(wù)器與數(shù)據(jù)庫)、命令行工具聯(lián)動(如ps | grep),還是復(fù)雜應(yīng)用的模塊通信,都離不開進(jìn)程間通信(IPC,Inter-Process Communication)。
今天我們就來系統(tǒng)梳理Linux中最常用的6種IPC方式,從原理到實(shí)例,從流程到適用場景,幫你徹底搞懂進(jìn)程間如何“對話”。
一、管道:最簡單的“單向傳送帶”
管道是Linux中最古老的IPC方式,本質(zhì)是內(nèi)核中的一塊緩沖區(qū),類似“傳送帶”——數(shù)據(jù)從一端寫入,從另一端讀出。
1.匿名管道(Pipe):只認(rèn)“自家人”
特點(diǎn):
?半雙工(數(shù)據(jù)只能單向流動),需創(chuàng)建兩個管道實(shí)現(xiàn)雙向通信;
?僅用于有親緣關(guān)系的進(jìn)程(父子、兄弟進(jìn)程,通過fork繼承管道描述符);
?隨進(jìn)程退出自動銷毀,不占用磁盤空間。
實(shí)例:父子進(jìn)程用匿名管道聊天
父進(jìn)程寫消息,子進(jìn)程讀消息:
#include#include #include intmain(){ intpipefd[2]; // 管道描述符:[0]讀端,[1]寫端 pipe(pipefd); // 創(chuàng)建匿名管道 pid_tpid = fork(); // 創(chuàng)建子進(jìn)程(繼承管道描述符) if(pid ==0) { // 子進(jìn)程:讀數(shù)據(jù) close(pipefd[1]); // 關(guān)閉寫端(只需要讀) charbuf[100]; read(pipefd[0], buf,sizeof(buf)); // 從管道讀 printf("子進(jìn)程收到:%sn", buf); close(pipefd[0]); }else{ // 父進(jìn)程:寫數(shù)據(jù) close(pipefd[0]); // 關(guān)閉讀端(只需要寫) char*msg ="Hi,我是父進(jìn)程!"; write(pipefd[1], msg,strlen(msg)+1); // 寫入管道 close(pipefd[1]); } return0;}
通信流程:

2.命名管道(FIFO):陌生人也能聊
特點(diǎn):
?與匿名管道功能類似,但通過文件系統(tǒng)中的路徑標(biāo)識(如/tmp/myfifo);
?可用于無親緣關(guān)系的進(jìn)程(只要知道FIFO路徑就能通信);
?是特殊文件(用mkfifo創(chuàng)建),但數(shù)據(jù)仍存于內(nèi)存,不落地。
實(shí)例:兩個獨(dú)立進(jìn)程通過FIFO通信
寫進(jìn)程(writer.c):
#include#include #include #include intmain(){ mkfifo("/tmp/myfifo",0666); // 創(chuàng)建FIFO文件 intfd =open("/tmp/myfifo", O_WRONLY); // 打開寫端 char*msg ="來自陌生進(jìn)程的消息"; write(fd, msg,strlen(msg)+1); close(fd); return0;}
讀進(jìn)程(reader.c):
#include#include #include #include intmain(){ intfd =open("/tmp/myfifo", O_RDONLY); // 打開讀端(會阻塞到有寫端打開) charbuf[100]; read(fd, buf,sizeof(buf)); printf("收到:%sn", buf); close(fd); return0;}
通信流程:

二、信號:進(jìn)程間的“緊急電報”
信號是Linux中最“輕量”的IPC方式,用于通知進(jìn)程發(fā)生了某種事件(如異常、用戶指令),類似“緊急電報”。
特點(diǎn):
?異步通信(無需進(jìn)程主動等待);
?攜帶信息少(僅一個信號編號);
?內(nèi)核負(fù)責(zé)遞送(進(jìn)程可注冊處理函數(shù))。
常用信號:
?SIGINT(2):用戶按Ctrl+C,默認(rèn)終止進(jìn)程;
?SIGTERM(15):請求進(jìn)程終止(默認(rèn)行為);
?SIGUSR1/SIGUSR2(10/12):用戶自定義信號。
實(shí)例:進(jìn)程A給進(jìn)程B發(fā)“自定義電報”
進(jìn)程B(接收方):
#include#include // 信號處理函數(shù)voidhandle_usr1(intsig){ printf("收到SIGUSR1信號!n");}intmain(){ signal(SIGUSR1, handle_usr1); // 注冊信號處理函數(shù) printf("我是進(jìn)程B,PID:%d,等待信號...n",getpid()); while(1); // 無限循環(huán)等待 return0;}
進(jìn)程A(發(fā)送方):
#include#include intmain(){ pid_tb_pid =12345; // 進(jìn)程B的PID(需替換為實(shí)際值) kill(b_pid, SIGUSR1); // 發(fā)送SIGUSR1信號給B printf("已發(fā)送SIGUSR1給進(jìn)程%dn", b_pid); return0;}
通信流程:

三、共享內(nèi)存:最快的“公共黑板”
共享內(nèi)存是速度最快的IPC方式——多個進(jìn)程直接訪問同一塊物理內(nèi)存,無需內(nèi)核“中轉(zhuǎn)”數(shù)據(jù)。
特點(diǎn):
?無數(shù)據(jù)拷貝(直接操作內(nèi)存),效率極高;
?需要同步機(jī)制(如信號量)防止“同時寫”沖突;
?由內(nèi)核管理(用shmget創(chuàng)建,shmctl銷毀)。
實(shí)例:兩個進(jìn)程共享一塊內(nèi)存
寫進(jìn)程(shm_write.c):
#include#include #include intmain(){ key_tkey =ftok(".",123); // 生成唯一鍵值 intshmid =shmget(key,1024, IPC_CREAT|0666); // 創(chuàng)建共享內(nèi)存(大小1024字節(jié)) char*shmaddr =shmat(shmid,NULL,0); // 關(guān)聯(lián)到進(jìn)程地址空間 strcpy(shmaddr,"共享內(nèi)存中的數(shù)據(jù)"); // 寫入數(shù)據(jù) shmdt(shmaddr); // 解除關(guān)聯(lián) return0;}
讀進(jìn)程(shm_read.c):
#include#include intmain(){ key_tkey =ftok(".",123); // 相同鍵值 intshmid =shmget(key,1024,0666); // 獲取共享內(nèi)存 char*shmaddr =shmat(shmid,NULL,0); // 關(guān)聯(lián)到地址空間 printf("讀到共享數(shù)據(jù):%sn", shmaddr); // 讀取數(shù)據(jù) shmdt(shmaddr); // 解除關(guān)聯(lián) shmctl(shmid, IPC_RMID,NULL); // 刪除共享內(nèi)存 return0;}
通信流程:

四、消息隊(duì)列:帶“標(biāo)簽”的“郵件箱”
消息隊(duì)列是內(nèi)核中的消息鏈表,每個消息有“類型標(biāo)簽”,進(jìn)程可按類型接收,類似“帶標(biāo)簽的郵件箱”。
特點(diǎn):
?數(shù)據(jù)有結(jié)構(gòu)(消息類型+數(shù)據(jù)),支持按類型讀??;
?異步通信(發(fā)送方無需等待接收方);
?有大小限制(內(nèi)核參數(shù)MSGMAX控制單條消息最大長度)。
實(shí)例:按類型發(fā)送/接收消息
發(fā)送進(jìn)程(msg_send.c):
#include#include #include // 消息結(jié)構(gòu)(必須以long mtype開頭)structmsgbuf{ longmtype; // 消息類型(正數(shù)) charmtext[100]; // 消息內(nèi)容};intmain(){ key_tkey =ftok(".",456); intmsqid =msgget(key, IPC_CREAT|0666); // 創(chuàng)建消息隊(duì)列 structmsgbufmsg; msg.mtype =1; // 類型為1 strcpy(msg.mtext,"類型1的消息"); msgsnd(msqid, &msg,sizeof(msg.mtext),0); // 發(fā)送消息 return0;}
接收進(jìn)程(msg_recv.c):
#include#include structmsgbuf{ longmtype; charmtext[100];};intmain(){ key_tkey =ftok(".",456); intmsqid =msgget(key,0666); // 獲取消息隊(duì)列 structmsgbufmsg; msgrcv(msqid, &msg,sizeof(msg.mtext),1,0); // 只接收類型1的消息 printf("收到類型%d的消息:%sn", msg.mtype, msg.mtext); msgctl(msqid, IPC_RMID,NULL); // 刪除消息隊(duì)列 return0;}
通信流程:

五、信號量:進(jìn)程同步的“紅綠燈”
信號量不是用于傳遞數(shù)據(jù),而是控制多個進(jìn)程對共享資源的訪問(如共享內(nèi)存、文件),類似“紅綠燈”。
核心概念:
?信號量值(semaphore):>=0的整數(shù),代表“可用資源數(shù)”;
?P操作(等待):信號量值- 1,若值< 0?則阻塞;
?V操作(釋放):信號量值+ 1,若有進(jìn)程阻塞則喚醒。
實(shí)例:用信號量保護(hù)共享內(nèi)存
(基于共享內(nèi)存,添加信號量控制):
#include// 定義P/V操作(簡化版)voidP(intsemid){ structsembufs = {0,-1,0}; // 第0個信號量,-1(P操作) semop(semid, &s,1);}voidV(intsemid){ structsembufs = {0,1,0}; // +1(V操作) semop(semid, &s,1);}// 初始化信號量(值為1,代表互斥)intinit_sem(){ key_tkey =ftok(".",789); intsemid =semget(key,1, IPC_CREAT|0666); semctl(semid,0, SETVAL,1); // 第0個信號量值設(shè)為1 returnsemid;}// 寫進(jìn)程在訪問共享內(nèi)存前P,寫完V;讀進(jìn)程同理
同步流程:

六、Socket:跨主機(jī)通信的“萬能接口”
Socket(套接字)是最靈活的IPC方式,不僅支持同一主機(jī)的進(jìn)程通信,還能跨網(wǎng)絡(luò)(如服務(wù)器與客戶端)。
特點(diǎn):
?支持TCP(可靠、面向連接)和UDP(不可靠、無連接);
?本地通信可用AF_UNIX協(xié)議(通過文件路徑標(biāo)識);
?網(wǎng)絡(luò)通信用AF_INET協(xié)議(通過IP +端口標(biāo)識)。
實(shí)例:本地Socket通信(AF_UNIX)
服務(wù)器(sock_server.c):
#include#include #include #include #include intmain(){ intsockfd =socket(AF_UNIX, SOCK_STREAM,0); // 創(chuàng)建本地套接字 structsockaddr_unaddr; addr.sun_family = AF_UNIX; strcpy(addr.sun_path,"/tmp/mysock"); // 本地路徑 bind(sockfd, (structsockaddr*)&addr,sizeof(addr)); // 綁定 listen(sockfd,5); // 監(jiān)聽 intconnfd =accept(sockfd,NULL,NULL); // 接受連接 charbuf[100]; read(connfd, buf,sizeof(buf)); printf("收到:%sn", buf); close(connfd); close(sockfd); unlink("/tmp/mysock"); // 刪除套接字文件 return0;}
客戶端(sock_client.c):
#include#include #include #include #include intmain(){ intsockfd =socket(AF_UNIX, SOCK_STREAM,0); structsockaddr_unaddr; addr.sun_family = AF_UNIX; strcpy(addr.sun_path,"/tmp/mysock"); connect(sockfd, (structsockaddr*)&addr,sizeof(addr)); // 連接服務(wù)器 char*msg ="本地Socket消息"; write(sockfd, msg,strlen(msg)+1); close(sockfd); return0;}
通信流程:

總結(jié):如何選擇合適的IPC方式?
| 方式 | 速度 | 復(fù)雜度 | 適用場景 |
| 匿名管道 | 中 | 低 | 父子進(jìn)程簡單單向通信 |
| 命名管道 | 中 | 中 | 無親緣關(guān)系進(jìn)程簡單通信 |
| 信號 | 快(異步) | 低 | 事件通知(如異常、退出) |
| 共享內(nèi)存 | 最快 | 高(需同步) | 高頻、大數(shù)據(jù)量共享 |
| 消息隊(duì)列 | 中 | 中 | 需按類型傳遞消息的場景 |
| 信號量 | 快 | 中 | 進(jìn)程同步與互斥(配合其他IPC) |
| Socket | 較慢 | 高 | 跨主機(jī)或復(fù)雜通信(如網(wǎng)絡(luò)服務(wù)) |
進(jìn)程間通信是Linux開發(fā)的核心基礎(chǔ),理解每種方式的優(yōu)缺點(diǎn),才能在實(shí)際場景中“對癥下藥”。比如日志收集可用命名管道,實(shí)時數(shù)據(jù)共享用共享內(nèi)存+信號量,網(wǎng)絡(luò)服務(wù)則離不開Socket。
你在開發(fā)中用過哪種IPC方式?遇到過哪些坑?歡迎在評論區(qū)交流~
-
Linux
+關(guān)注
關(guān)注
88文章
11595瀏覽量
217479 -
IPC
+關(guān)注
關(guān)注
3文章
375瀏覽量
54382
發(fā)布評論請先 登錄
嵌入式Linux進(jìn)程 -進(jìn)程間通信
Linux進(jìn)程間的五種通信方式介紹 3
Linux進(jìn)程間的五種通信方式介紹 4
Linux進(jìn)程間的五種通信方式介紹 6
Linux進(jìn)程間的五種通信方式介紹 5
如何實(shí)現(xiàn)一套linux進(jìn)程間通信的機(jī)制

Linux進(jìn)程間通信(IPC)全解析:從管道到?Socket,一篇講透
評論