ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

进程间通信--管道

进程间通信--管道 目录一、管道1.1 匿名管道1.2 管道的特性1.2 命名管道1.2.1 用命名管道实现serverclient通信一、管道1.1 匿名管道#includeunistd.h功能:创建⼀⽆名管道原型intpipe(intfd[2]);参数fd⽂件描述符数组,其中fd[0]表⽰读端, fd[1]表⽰写端返回值:成功返回0失败返回错误代码管道通信前提是让不同进程看到同一份资源-- 文件 -- 文件的内核缓冲区---内存块1. 父进程创建管道2 父进程创建子进程 然后父子进程都看到了同一个资源父进程关闭fd[0] 子进程关闭fd[1]1.2 管道的特性1. 管道只能单向通信单工通信2. 匿名管道只能用来进行父子通信有血缘关系的就行常用父子3. 管道是面向字节流的4. 管道的生命周期是随进程的5. 管道通信对于多进程而言是自带互斥与同步机制互斥与同步的解释举个简单的例子你在图书馆读一本书在一个位子上然后来电话了然后你回来发现位子被占为了解决这个问题同步就是访问数据具有一定的顺序性如公交车按顺序上车互斥就是任何时刻只允许一个人访问资源。4种情况1. 子进程写的慢父进程要阻塞等管道有数据父进程才能读2. 子进程写得快父进程不读管道一旦被写满子进程必须堵塞-- 让父进程读3. 读端在读写端关闭读端读完管道剩余数据再读就会读取“”read返回0表明读结尾4. 写端一直写读端不读关闭fdos会直接杀死写的进程第四条证明#include stdio.h #include unistd.h #include stdlib.h #include string.h #include sys/types.h #include sys/wait.h int main() { // 1 创建管道 int pipefd[2] {0}; int n pipe(pipefd); if(n -1) { perror(pipe); return 1; } printf(pipefd[0]: %d, pipefd[1]: %d\n, pipefd[0], pipefd[1]); // fork 创建子进程 pid_t pid fork(); if(pid 0) { // 子进程 : w close(pipefd[0]); char *msg hello world; // write(pipefd[1], msg, sizeof(msg)); int cnt 10; char outbuf[1024] {0}; // char ch A; // int size 0; while(1){ // write(pipefd[1], ch, 1); // size; // printf(write: %c, size: %d\n, ch, size); snprintf(outbuf, sizeof(outbuf), c - f# %s %d %d\n, msg, cnt--, getpid()); write(pipefd[1], outbuf, strlen(outbuf)); sleep(1); // sleep(1); // close(pipefd[1]); // break; // if(cnt % 3 0) { // sleep(1); // } } printf(child process exit\n); close(pipefd[1]); exit(0); } // 父进程 : r close(pipefd[1]); char buf[1024] {0}; // read(pipefd[0], buf, sizeof(buf)); char inbuf[1024] {0}; while(1) { // sleep(100); ssize_t n read(pipefd[0], inbuf, sizeof(inbuf)-1); if(n 0) { inbuf[n] \0; printf(read: %s 返回值: %ld\n, inbuf, n); } else if(n 0) { printf(pipe closed\n); break; } else { perror(read failed); break; } close(pipefd[0]); break; // printf(read: %s 返回值: %ld\n, inbuf, n); // sleep(1); } sleep(10); int status 0; pid_t rid waitpid(pid, status, 0); if(rid 0) { printf(child quit code %d , signal: %d\n, (status 8)0xff, status 0x7f); } return 0; }1.2 命名管道如果两个毫无关系的进程该如何通信呢进程进行通信还是让两个进程看到同一份资源你怎么保证打开的是同一份文件只要访问同一个路径下的同一个文件即可 路径文件名唯一的inode创建命名管道intmain(intargc,char*argv[]){mkfifo(p2,0644);return0;}1.2.1 用命名管道实现serverclient通信.PHONY:all all:Client Server Server:Server.cc g -o $ $^ -stdc11 Client:Client.cc g -o $ $^ -stdc11 .PHONY:clean clean: rm -f Server ClientPipe.hpp1. 创建管道 首先要判断是否存在管道不能用open去判断因为只打开了一端因此会堵塞。只能用stat来判断2. 打开管道 要注意的就是谁创建谁删除3. 删除管道 使用unlink去删除#pragma once #include iostream #include string #include sys/types.h #include sys/stat.h #include stdlib.h #include cstring #include errno.h #include unistd.h #include fcntl.h #define ForRead 1 #define ForWrite 2 const std::string gcommfile ./fifo; class Fifo { public: Fifo(const std::string commfile gcommfile) : _commfile(commfile), _mode(0666), _fd(-1) { } // 1 创建管道 void Build() { if(IsExists()) return ; int n mkfifo(_commfile.c_str(), _mode); if (n 0) { std::cerr mkfifo error: strerror(errno) errno: errno std::endl; exit(1); } std::cerr mkfifo success: strerror(errno) errno: errno std::endl; } // 2 打开管道 void Open(int mode) { // r or w if(mode ForRead) { _fd open(_commfile.c_str(), O_RDONLY); } else if(mode ForWrite) { _fd open(_commfile.c_str(), O_WRONLY); } if(_fd 0) { std::cerr mkfifo error: strerror(errno) errno: errno std::endl; exit(2); } else { std::cout open success! std::endl; } } void Send(const std::string msgin) { ssize_t n write(_fd, msgin.c_str(), msgin.size()); } int Recv(std::string *msgout) { char buffer[128]; ssize_t n read(_fd, buffer, sizeof(buffer) - 1); // 为什么要减1 if(n 0) { buffer[n] \0; *msgout buffer; return n; } else if(n 0) { return 0; } else { return -1; } } // 3 删除管道 void Delete() { if(!IsExists()) return ; int n unlink(_commfile.c_str()); std::cout unlink _commfile std::endl; } ~Fifo() {} private: bool IsExists() { // 不可以使用open来判断 struct stat st; int n stat(_commfile.c_str(), st); if(n 0) { std::cout file exist std::endl; return true; } else { std::cout file not exist: errno std::endl; errno 0; return false; } } private: std::string _commfile; mode_t _mode; int _fd; };Service.cc#include iostream #include Pipe.hpp int main() { Fifo pipefile; pipefile.Build(); pipefile.Open(ForRead); std::string msg; while(true) { int n pipefile.Recv(msg); if(n 0) std::cout clent say# msg std::endl; else break; } pipefile.Delete(); return 0; }Client.cc#include iostream #include Pipe.hpp int main() { Fifo fileclient; fileclient.Open(ForWrite); while (true) { std::cout Please Enter# ; std::string msg; std::getline(std::cin, msg); fileclient.Send(msg); } return 0; }
返回列表