进程通信管道制作
利用父子進程
創建管道利用pipe函數
// 1.創建管道int pipefd[2] = {0}; //[0] 讀端 ,[1]寫端int n = pipe(pipefd);assert(n != -1); // debug 在release下會裁減(void)n;//防止在release下報錯cout << "fd[0]:" << pipefd[0] << endl; // 3cout << "fd[1]:" << pipefd[1] << endl; // 4pipe該函數內會創建一個管道文件,我們需要手動傳入一個整型數組保存兩個元素。
當函數返回繼續檢查。注意我們的pipefd[0]為對管道讀端,pipe[1]為對管道寫端,保存的是文件描述符fd。
pid_t id = fork();assert(id != -1);//父進程寫入,子進程讀取if (id == 0){//子進程//構建單項通信int end=0;close(pipefd[1]); //關閉子進程prpefd[1]。//char buff[1024];while (1){//子進程工作}close(pipefd[0]);exit(0);}fork()創建子進程通過id判斷是否為子進程,如果是0子進程就進入 if 判斷式。
子進程繼承父進程的進程一眾數據結構,那么files_struct也是一樣的,所以我們通過fd也可以訪問文件。子進程讀取數據,就要將寫端關閉(也可不關),close(pipefd[1]);然后進行通信工作。
結束后關閉讀端,然后結束子進程。
// 父進程//構建單項通信close(pipefd[0]);char send_buff[1024 ];while (1){//父進程寫入工作}//工作結束close(pipefd[1]);//回收子進程pid_t ret = waitpid(id, nullptr, 0);assert(ret != -1);return 0; }父進程關閉讀端(也可以不關閉),創建緩沖區,進行寫入工作,當工作結束關閉對管道的寫端。
然后等待子進程結束回收資源。判斷是否正確回收。結束進程。
有一些情況:管道文件,提供了協同工作的機理。讀寫同步。
寫段關閉,讀端進程會讀取到文件結尾,退出循環。
讀端關閉,寫端進程被操作系統強行嗝屁。(子進程變為孤兒進程)。
完整代碼
#include <iostream> #include <unistd.h> #include <cstdio> #include <cstring> #include <assert.h> #include <string> #include <string.h> #include <sys/types.h> #include <sys/wait.h> using namespace std;int main() {// 1.創建管道int pipefd[2] = {0}; //[0] 讀端 ,[1]寫端int n = pipe(pipefd);assert(n != -1); // debug 在release下會裁減(void)n; #ifdef DEBUGcout << "fd[0]:" << pipefd[0] << endl; // 3cout << "fd[1]:" << pipefd[1] << endl; // 4 #endifpid_t id = fork();assert(id != -1);//父進程寫入,子進程讀取if (id == 0){//子進程//構建單項通信int end=0;close(pipefd[1]); //關閉子進程prpefd[1]。char buff[1024];while (1){ssize_t s = read(pipefd[0], buff, sizeof(buff) - 1);if (s > 0){buff[s] = '\0';cout << "child:pid[" << getpid() << "]father#" << buff << endl;}else if (s == 0){printf("寫入方關閉寫端\n");break;}cout<<"end:"<<end<<endl;if(end++==5){cout<<"寫端提前關閉"<<endl;break;}}cout<<"子進程關閉讀端"<<endl;close(pipefd[0]);// close(pipefd[0]);exit(0);}// 父進程//構建單項通信close(pipefd[0]);string parent("我是父進程!!!我在發信息");int cnt = 0;char send_buff[1024];while (1){memset(send_buff,0,sizeof(send_buff));snprintf(send_buff, sizeof(send_buff), "%s[%d次]:ppid=%d", parent.c_str(), cnt++, getpid());// 3.3寫入管道sleep(1);int m = write(pipefd[1], send_buff, strlen(send_buff));cout << cnt << endl;if (m < 0){printf("寫入失敗\n");}sleep(1);}printf("父進程關閉寫端\n");close(pipefd[1]);sleep(10);pid_t ret = waitpid(id, nullptr, 0);assert(ret != -1);return 0; }非父子進程管道通信。
創建兩個進程,通過管道進行通信鏈接。
首先先介紹,mkfifo函數,顯示的創建一個管道文件,
int mkfifo(const char *pathname, mode_t mode);pathname:創建管道的文件名字以及路徑。
mode:管道文件權限設置。
我們的兩個進程需要同時訪問同一個管道文件,所以我們創建的路徑一定要一致。我們讓兩個源代碼使用同一頭文件。
//pipe.hpp #ifndef _COMM_H_ #define _COMM_H_ #include<cstdio> #include<cstring> #include<iostream> #include<unistd.h> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include"Log.hpp" #define MODE 0666 #define SIZE 128 using namespace std; string ipcPath("./fifi.ipc");//可絕對可相對,為了簡便我們使用相對路徑 #endif創建一個string 類,管道文件保存路徑,兩個包含該頭文件的源代碼就可以訪問到相同的管道文件了。
我們在讀取數據方創建管道文件(也可以在發送數據方)
int main() {//創建管道if(mkfifo(ipcPath.c_str(),MODE)<0){perror("mkfifo fail!\n");exit(-1);}Log("管道創建成功",Debug)<<"stap 1"<<endl;//日志信息創建管道,會在當前目錄下生成,管道文件
?當前進程鏈接管道。
//鏈接管道int fd=open(ipcPath.c_str(),O_RDONLY);if(fd==-1){perror("open");exit(-2);}Log("管道打開成功",Debug)<<"stap 2"<<endl;//日志信息如果管道寫端沒有被訪問,會在管道內阻塞讀端進程
寫端進程運行?
讀端停止阻塞,繼續運行。
//使用管道開始通信char buffer[SIZE];while(1){memset(buffer,0,sizeof(buffer));ssize_t s=read(fd,buffer,sizeof(buffer)-1);if(s>0){buffer[s]='\0';cout<<buffer<<endl;}else if(s==0){printf("file read end,end receive colse\n");break;}else{printf("read error!!!\n");exit(-3);}}開始讀取工作。
當我們關閉寫端。
close(fd);Log("管道關閉成功",Debug)<<"stap 3"<<endl;unlink(ipcPath.c_str());Log("管道刪除成功",Debug)<<"stap 4"<<endl;return 0; }我們先關閉fd文件描述符,在刪除管道文件。
讀端完整代碼
#include"commt.hpp"int main() {//創建管道if(mkfifo(ipcPath.c_str(),MODE)<0){perror("mkfifo fail!\n");exit(-1);}Log("管道創建成功",Debug)<<"stap 1"<<endl;//鏈接管道int fd=open(ipcPath.c_str(),O_RDONLY);if(fd==-1){perror("open");exit(-2);}Log("管道打開成功",Debug)<<"stap 2"<<endl;//使用管道開始通信char buffer[SIZE];while(1){memset(buffer,0,sizeof(buffer));ssize_t s=read(fd,buffer,sizeof(buffer)-1);if(s>0){buffer[s]='\0';cout<<buffer<<endl;}else if(s==0){printf("file read end,end receive colse\n");break;}else{printf("read error!!!\n");exit(-3);}}close(fd);Log("管道關閉成功",Debug)<<"stap 3"<<endl;unlink(ipcPath.c_str());Log("管道刪除成功",Debug)<<"stap 4"<<endl;return 0; }相比讀端我們的寫端代碼量輕松的多。
#include"commt.hpp"int main() {//打開管道int fd=open(ipcPath.c_str(),O_WRONLY);if(fd<-1){perror("open fail!\n");exit(-1);}string buffer;while(1){cout<<"Plase Enter Message Line >";std::getline(std::cin,buffer);write(fd,buffer.c_str(),buffer.size());}close(fd);return 0; }?寫端只需要普通的文件操作,要注意的是需要打開同一個管道文件,進行寫入。在運行結束的時候關閉fd即可,刪除管道文件在讀端進程完成。
?
總結
- 上一篇: 机房环境综合监测主机
- 下一篇: 计算机技术与软件专业以考代评政策之我见