进程通信管道制作
利用父子進(jìn)程
創(chuàng)建管道利用pipe函數(shù)
// 1.創(chuàng)建管道int pipefd[2] = {0}; //[0] 讀端 ,[1]寫端int n = pipe(pipefd);assert(n != -1); // debug 在release下會(huì)裁減(void)n;//防止在release下報(bào)錯(cuò)cout << "fd[0]:" << pipefd[0] << endl; // 3cout << "fd[1]:" << pipefd[1] << endl; // 4pipe該函數(shù)內(nèi)會(huì)創(chuàng)建一個(gè)管道文件,我們需要手動(dòng)傳入一個(gè)整型數(shù)組保存兩個(gè)元素。
當(dāng)函數(shù)返回繼續(xù)檢查。注意我們的pipefd[0]為對(duì)管道讀端,pipe[1]為對(duì)管道寫端,保存的是文件描述符fd。
pid_t id = fork();assert(id != -1);//父進(jìn)程寫入,子進(jìn)程讀取if (id == 0){//子進(jìn)程//構(gòu)建單項(xiàng)通信int end=0;close(pipefd[1]); //關(guān)閉子進(jìn)程prpefd[1]。//char buff[1024];while (1){//子進(jìn)程工作}close(pipefd[0]);exit(0);}fork()創(chuàng)建子進(jìn)程通過(guò)id判斷是否為子進(jìn)程,如果是0子進(jìn)程就進(jìn)入 if 判斷式。
子進(jìn)程繼承父進(jìn)程的進(jìn)程一眾數(shù)據(jù)結(jié)構(gòu),那么files_struct也是一樣的,所以我們通過(guò)fd也可以訪問(wèn)文件。子進(jìn)程讀取數(shù)據(jù),就要將寫端關(guān)閉(也可不關(guān)),close(pipefd[1]);然后進(jìn)行通信工作。
結(jié)束后關(guān)閉讀端,然后結(jié)束子進(jìn)程。
// 父進(jìn)程//構(gòu)建單項(xiàng)通信close(pipefd[0]);char send_buff[1024 ];while (1){//父進(jìn)程寫入工作}//工作結(jié)束close(pipefd[1]);//回收子進(jìn)程pid_t ret = waitpid(id, nullptr, 0);assert(ret != -1);return 0; }父進(jìn)程關(guān)閉讀端(也可以不關(guān)閉),創(chuàng)建緩沖區(qū),進(jìn)行寫入工作,當(dāng)工作結(jié)束關(guān)閉對(duì)管道的寫端。
然后等待子進(jìn)程結(jié)束回收資源。判斷是否正確回收。結(jié)束進(jìn)程。
有一些情況:管道文件,提供了協(xié)同工作的機(jī)理。讀寫同步。
寫段關(guān)閉,讀端進(jìn)程會(huì)讀取到文件結(jié)尾,退出循環(huán)。
讀端關(guān)閉,寫端進(jìn)程被操作系統(tǒng)強(qiáng)行嗝屁。(子進(jìn)程變?yōu)楣聝哼M(jìn)程)。
完整代碼
#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.創(chuàng)建管道int pipefd[2] = {0}; //[0] 讀端 ,[1]寫端int n = pipe(pipefd);assert(n != -1); // debug 在release下會(huì)裁減(void)n; #ifdef DEBUGcout << "fd[0]:" << pipefd[0] << endl; // 3cout << "fd[1]:" << pipefd[1] << endl; // 4 #endifpid_t id = fork();assert(id != -1);//父進(jìn)程寫入,子進(jìn)程讀取if (id == 0){//子進(jìn)程//構(gòu)建單項(xiàng)通信int end=0;close(pipefd[1]); //關(guān)閉子進(jìn)程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("寫入方關(guān)閉寫端\n");break;}cout<<"end:"<<end<<endl;if(end++==5){cout<<"寫端提前關(guān)閉"<<endl;break;}}cout<<"子進(jìn)程關(guān)閉讀端"<<endl;close(pipefd[0]);// close(pipefd[0]);exit(0);}// 父進(jìn)程//構(gòu)建單項(xiàng)通信close(pipefd[0]);string parent("我是父進(jìn)程!!!我在發(fā)信息");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("父進(jìn)程關(guān)閉寫端\n");close(pipefd[1]);sleep(10);pid_t ret = waitpid(id, nullptr, 0);assert(ret != -1);return 0; }非父子進(jìn)程管道通信。
創(chuàng)建兩個(gè)進(jìn)程,通過(guò)管道進(jìn)行通信鏈接。
首先先介紹,mkfifo函數(shù),顯示的創(chuàng)建一個(gè)管道文件,
int mkfifo(const char *pathname, mode_t mode);pathname:創(chuàng)建管道的文件名字以及路徑。
mode:管道文件權(quán)限設(shè)置。
我們的兩個(gè)進(jìn)程需要同時(shí)訪問(wèn)同一個(gè)管道文件,所以我們創(chuàng)建的路徑一定要一致。我們讓兩個(gè)源代碼使用同一頭文件。
//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");//可絕對(duì)可相對(duì),為了簡(jiǎn)便我們使用相對(duì)路徑 #endif創(chuàng)建一個(gè)string 類,管道文件保存路徑,兩個(gè)包含該頭文件的源代碼就可以訪問(wèn)到相同的管道文件了。
我們?cè)谧x取數(shù)據(jù)方創(chuàng)建管道文件(也可以在發(fā)送數(shù)據(jù)方)
int main() {//創(chuàng)建管道if(mkfifo(ipcPath.c_str(),MODE)<0){perror("mkfifo fail!\n");exit(-1);}Log("管道創(chuàng)建成功",Debug)<<"stap 1"<<endl;//日志信息創(chuàng)建管道,會(huì)在當(dāng)前目錄下生成,管道文件
?當(dāng)前進(jìn)程鏈接管道。
//鏈接管道int fd=open(ipcPath.c_str(),O_RDONLY);if(fd==-1){perror("open");exit(-2);}Log("管道打開成功",Debug)<<"stap 2"<<endl;//日志信息如果管道寫端沒(méi)有被訪問(wèn),會(huì)在管道內(nèi)阻塞讀端進(jìn)程
寫端進(jìn)程運(yùn)行?
讀端停止阻塞,繼續(xù)運(yùn)行。
//使用管道開始通信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);}}開始讀取工作。
當(dāng)我們關(guān)閉寫端。
close(fd);Log("管道關(guān)閉成功",Debug)<<"stap 3"<<endl;unlink(ipcPath.c_str());Log("管道刪除成功",Debug)<<"stap 4"<<endl;return 0; }我們先關(guān)閉fd文件描述符,在刪除管道文件。
讀端完整代碼
#include"commt.hpp"int main() {//創(chuàng)建管道if(mkfifo(ipcPath.c_str(),MODE)<0){perror("mkfifo fail!\n");exit(-1);}Log("管道創(chuàng)建成功",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("管道關(guān)閉成功",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; }?寫端只需要普通的文件操作,要注意的是需要打開同一個(gè)管道文件,進(jìn)行寫入。在運(yùn)行結(jié)束的時(shí)候關(guān)閉fd即可,刪除管道文件在讀端進(jìn)程完成。
?
總結(jié)
- 上一篇: 机房环境综合监测主机
- 下一篇: 计算机技术与软件专业以考代评政策之我见