IPC
1.什么是IPC?Inter Process Communication
2.進程間通信常用的幾種方式
????????1,管道通信:有名管道,無名管道
????????2,信號- 系統開銷小
????????3,消息隊列-內核的鏈表
????????4,信號量-計數器
????????5,共享內存
????????6,內存映射
????????7,套接字
無名管道
管道的概念
1.本質
內核緩沖區
偽文件-不占用磁盤空間
2特點:
兩部分: 讀端,寫端,對應兩個文件描述符
數據寫端流入,讀端流出
操作管理的進程被銷毀之后,管道自動被釋放
管道默認是阻塞的
管道的原理
1.內部實現方式:
隊列-環形隊列
特點:先進先出
2.緩沖區大小
默認4K,大小會根據實際情況做適當調整
管道的局限性
1.隊列: 數據只能讀取一次,不能重復讀取
2.半雙工:
單工:遙控器
半雙工:對講機
創建匿名管道
int?pipe(int?fd[2])
fd‐傳出參數:
????????fd[0]‐讀端
????????fd[1]‐寫端
返回值:
????????0:成功
????????‐1:創建失敗
父子進程使用管道通信
實現 ps aux | grep "bash"
數據重定向:dup2
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>int main()
{int ret;int fd[2];ret = pipe(fd);if(ret == -1){printf("pipe creat failed\n");exit(1);}printf("pipe creat success!\n");printf("fd[0] is %d\n",fd[0]);printf("fd[1] is %d\n",fd[1]);close(fd[0]);close(fd[1]);return 0;
}
~
注012是標準輸入輸出和報錯
? ? ? ?int dup2(int oldfd, int newfd);//新段指向舊端
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>int main()
{pid_t pid;int ret;int fd[2];ret = pipe(fd);if(ret == -1){printf("pipe creat failed\n");exit(1);}printf("pipe creat success!\n");pid = fork();if(pid == -1){printf("fork failed\n");exit(1);}if(pid > 0){close(fd[0]);dup2(fd[1],STDOUT_FILENO);execlp("ps","ps","aux",NULL);perror("excelp");exit(1);}else if (pid == 0){close(fd[1]);dup2(fd[0],STDIN_FILENO);execlp("grep","grep","bash","--color=auto",NULL);}return 0;
}
單個進程也可以使用管道
父子進程在使用管道的時候,父進程寫的時候要關閉讀,子進程讀的時候要關閉寫?
管道的讀寫行為
1.讀操作
? ? ? ? 1)有數據:read(fd[0]) 正常讀,返回讀出的字節數
? ? ? ? 2)無數據:
????????????????寫端被全部關閉,read返回0,相當于讀文件到了尾部
????????????????沒有全部關閉,read阻塞
2.寫操作
? ? ? ? 1)讀端全部關閉:
????????????????管道破裂,進程被終止
????????????????內核給當前進程發送信號SIGPIPE-13,默認處理動作
? ? ? ? 2)讀端沒全部關閉:
????????????????緩沖區寫滿了,write阻塞
????????????????緩沖區沒滿,write繼續寫,直到寫滿,阻塞
3.如何設置非阻塞?
1)默認讀寫兩端都阻塞
2)設置讀端為非阻塞pipe(fd):
????????fcntl-變參函數:復制文件描述符-dup;修改文件屬性-open的時候對應flag屬性
????????設置方法
//獲取原來的flags?
int?flags?=?fcntl(fd[0],F+GETFL);?
//設置新的flags?
flag?|=O_NONBLOCK;?
fcntl(fd[0],F_SETFL,flags);?
fcntl(fd[0],F_SETFL,flags);?
查看管道緩沖區大小
命令:
ulimit -a
fpathconf
? long fpathconf(int fd, int name);
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>int main()
{int ret;int fd[2];ret = pipe(fd);if(ret == -1){printf("pipe creat failed\n");exit(1);}printf("pipe creat success!\n");long size = fpathconf(fd[0],_PC_PIPE_BUF);printf("size id %ld\n",size);printf("fd[0] is %d\n",fd[0]);printf("fd[1] is %d\n",fd[1]);close(fd[0]);close(fd[1]);return 0;
}
有名管道
函數形式:int?mkfifo(const?char?\*filename,mode_t?mode);
功能:創建管道文件
參數:管道文件文件名,權限,創建的文件權限仍然和umask有關系。
返回值:創建成功返回0,創建失敗返回-1。
特點
????????有名管道
????????在磁盤上有這樣一個文件 ls -l ->p
????????也是一個偽文件,在磁盤大小永久為0
????????數據存在內核中有一個對應的緩沖區
????????半雙工通信方式
使用場景
沒有血緣關系的進程間通信
創建方式
命令:mkfifo 管道名
函數:mkfifo()
?int mkfifo(const char *pathname, mode_t mode);
fifo文件可以使用io函數進程操作
open/close,read/write
不能執行lseek操作
讀函數
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main()
{int ret;int fd;int nread;char readBuff[50] = {0};ret = mkfifo("/home/u/process/myfifo",0777);if(ret == -1){return -1;}printf("creat file success!\n");fd = open("./myfifo",O_RDONLY);if(fd < 0){return -1;}printf("open file success!\n");nread = read(fd,readBuff,50);printf("read %d byte from fifo :%s\n",nread,readBuff);close(fd);return 0;
}
寫程序
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main()
{int fd;char *str = "hello world!";fd = open("./myfifo",O_WRONLY);if(fd < 0){return -1;}printf("open file success!\n");write(fd,str,strlen(str));close(fd);return 0;
}
~