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

2.命名管道(FIFO):陌生人也能聊
特點:
?與匿名管道功能類似,但通過文件系統(tǒng)中的路徑標識(如/tmp/myfifo);
?可用于無親緣關系的進程(只要知道FIFO路徑就能通信);
?是特殊文件(用mkfifo創(chuàng)建),但數(shù)據(jù)仍存于內(nèi)存,不落地。
實例:兩個獨立進程通過FIFO通信
寫進程(writer.c):
#include#include #include #include intmain(){ mkfifo("/tmp/myfifo",0666); // 創(chuàng)建FIFO文件 intfd =open("/tmp/myfifo", O_WRONLY); // 打開寫端 char*msg ="來自陌生進程的消息"; write(fd, msg,strlen(msg)+1); close(fd); return0;}
讀進程(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;}
通信流程:

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

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

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

五、信號量:進程同步的“紅綠燈”
信號量不是用于傳遞數(shù)據(jù),而是控制多個進程對共享資源的訪問(如共享內(nèi)存、文件),類似“紅綠燈”。
核心概念:
?信號量值(semaphore):>=0的整數(shù),代表“可用資源數(shù)”;
?P操作(等待):信號量值- 1,若值< 0?則阻塞;
?V操作(釋放):信號量值+ 1,若有進程阻塞則喚醒。
實例:用信號量保護共享內(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個信號量值設為1 returnsemid;}// 寫進程在訪問共享內(nèi)存前P,寫完V;讀進程同理
同步流程:

六、Socket:跨主機通信的“萬能接口”
Socket(套接字)是最靈活的IPC方式,不僅支持同一主機的進程通信,還能跨網(wǎng)絡(如服務器與客戶端)。
特點:
?支持TCP(可靠、面向連接)和UDP(不可靠、無連接);
?本地通信可用AF_UNIX協(xié)議(通過文件路徑標識);
?網(wǎng)絡通信用AF_INET協(xié)議(通過IP +端口標識)。
實例:本地Socket通信(AF_UNIX)
服務器(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)); // 連接服務器 char*msg ="本地Socket消息"; write(sockfd, msg,strlen(msg)+1); close(sockfd); return0;}
通信流程:

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