进程间通信(一)
進程間通信
文章目錄
- 進程間通信
- 一、進程間通信簡介
- 二、進程間通訊的發展及分類:
- 三、管道
- 四、minishell
一、進程間通信簡介
- 1.進程間是相互獨立的,每個進程都有自己的進程虛擬地址空間,二進程通訊需要介子,使得兩個進程都能訪問的公共資源;
- 2.進程間通訊的目的:
- 數據傳輸:一個進程需要將他的數據發送給另一個進程
- 資源共享:多個進程間共享同樣的資源
- 通知事件:一個進程需要向另一個或一組進程發送消息,通知它們發生了某種事件(如子進程退出時要通知父進程回收其資源等)
- 進程控制:有些進程希望完全控制另一個進程的執行,此時控制進程希望能夠攔截另一個進程所有陷入和異常,并能及時的知道他的改變狀態
二、進程間通訊的發展及分類:
- 1.管道
- 匿名管道pipe
- 命名管道
- 2.System V進程間通訊
- System V消息共享隊列
- System V共享內存
- System V信號量
- 3.POSIX進程間通訊
- 消息隊列
- 共享內存
- 信號量
- 互斥量
- 條件變量
- 讀寫鎖
三、管道
-
1.什么是管道:管道是內核中的一塊內存,構成一個隊列,使用一對文件描述符來進行訪問管理這個內存,讀文件描述符相當于從這個內存中取數據,寫文件描述符相當于往這塊內存中寫數據
-
2.匿名管道
-
匿名管道的創建
-
功能:是創建一個無名管道;
-
參數:是兩個輸出型參數,fd表示文件描述符數組,其中fd[0]端表示讀端,fd[1]端表示寫端。
-
返回值:創建成功返回0;失敗返回錯誤碼。
測試代碼:
- 3.用fork來共享管道
站在文件描述符的角度:
站在內核角度:
共享管道實用的注意事項:
四、minishell
#include <stdio.h> #include <sys/wait.h> #include <ctype.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h>char g_command[1024]; static char* pipe_command[] = {0};//該函數的功能是獲取命令行輸入的數據 int GetCommand() {//因為開始獲得的內存中的內容是不定的,所以使用前要先初始化memset(g_command,'\0',sizeof(g_command));//這里需要為'\0'留一個位置,不能把g_command全部用來讀取內容,否者就沒有結束標志,容易發生內存訪問越界if(fgets(g_command,sizeof(g_command)-1,stdin)==NULL){printf("fgets is error!\n");return -1;}//printf("g_command:%s\n",g_command);return 0; }//解析字符串 char** DealCommand(char* command) {if(command==NULL&&*command=='\0'){printf("dealcommand is error\n");return NULL;}//用來保存命令static char* argv[1024]={0};int argc=0;while(*command){//isspace函數用來去掉多余的空格//isspace的返回值:如果當前字符是空格返回1,否則返回0//注意'\0'在issapce函數中不算空格的,所以要進行判斷while(!isspace(*command)&&*command!='\0'){argv[argc]=command;argc++;//去找下一個空格while(!isspace(*command)&&*command!='\0'){command++;}*command='\0';}command++;}argv[argc]=NULL;//for(int i=0;i<argc;i++)//{// printf("%d:%s ",i,argv[i]);//}//printf("\n");return argv; }//進行重定向 int redirect(char * g_command) {char* ptr = g_command;char* file = NULL;int fd ;//用來標記是清空重定向還是追加重定向int redirect_type = -1;while(*ptr !='\0'){//如果當前字符是 > ,把他置為'\0',并判斷下一個位置是否為'\0'if(*ptr == '>'){*ptr++ = '\0';redirect_type++;if(*ptr == '>'){*ptr++ = '\0';redirect_type++;}//去掉多余的空格while(isspace(*ptr)){ptr++;}//file就是空格后面的第一個字符串file = ptr;//繼續找空格,在這兩個空格之間就是文件的名稱while(!isspace(*ptr)&&*ptr != '\0'){ptr++;}*ptr='\0';//如果redirect_type==0說明是清空重定向,如果==1說明是追加重新定向if(redirect_type == 0){fd = open(file,O_CREAT|O_TRUNC|O_WRONLY,0664);}else{fd = open(file,O_CREAT|O_APPEND|O_WRONLY,0664);}dup2(fd,1);}ptr++;}return 0; }//解析字符串,獲取管道的數量 int do_command(char * g_command) {int pipe_num = 0;char * ptr =g_command;pipe_command[pipe_num]=ptr;while(*ptr != '\0'){if(*ptr == '|'){pipe_num++;*ptr++ = '\0';pipe_command[pipe_num] = ptr;continue;}ptr++;}pipe_command[pipe_num + 1] = NULL;return pipe_num; }//進行程序替換 int exec() {redirect(g_command);char** argv=DealCommand(g_command);pid_t pid =fork();if(pid<0){printf("foek is error!\n");return -1;}else if(pid==0){//child//如果argc中為NULL,就直接返回if(argv[0]==NULL){exit(-1);}//進行替換,execvp第一個參數是可執行程序名,第二個參數是該可執行程序的參數組成的數組execvp(argv[0],argv);//execl("/usr/bin/ls","ls","-a",NULL);}else{//fatherwaitpid(pid,NULL,0);}return 0; }//添加管道功能 int do_pipe(int pipe_num) {int pid = 0;int i;int pipefd[10][2] = {{0}};char** argv = {NULL};for (i = 0;i <= pipe_num;i++){pipe(pipefd[i]);}for(i = 0;i <= pipe_num; i++){pid = fork();if(pid < 0){perror("fork is error!\n");continue;}else if(pid == 0){redirect(pipe_command[i]);argv = DealCommand(pipe_command[i]);if(i != 0){close(pipefd[i][1]);dup2(pipefd[i][0],0);}if(i != pipe_num){close(pipefd[i+1][0]);dup2(pipefd[i+1][1],1);}execvp(argv[0],argv);}else{close(pipefd[i][0]);close(pipefd[i][1]);waitpid(pid,NULL,0);}}return 0; }int main() {//循環讀數據while(1){printf("[dev@localhost dev]$ ");int ret = GetCommand();if(ret == -1){//如果讀取失敗,繼續循環讀取,不能直接break調continue;}//處理解析數據//char** argv = DealCommand(g_command);//進行替換//exec(argv);//exec();int num = do_command(g_command);do_pipe(num);}return 0; }總結
- 上一篇: Linux中的基础IO(二)
- 下一篇: 进程间通信(二)