去哪找网站建设公司好,怎么做线上营销,网站宣传需要多少钱,建网站作业如何创建命名管道
使用mkfifo函数就可以在程序里面创建管道文件#xff0c;该函数的声明如下#xff1a; 该函数需要两个参数#xff0c;第一个参数表示要在哪个路径下创建管道文件并且这个路径得待上管道文件的名字#xff0c;因为每个文件都有对应的权限#xff0c;所…如何创建命名管道
使用mkfifo函数就可以在程序里面创建管道文件该函数的声明如下 该函数需要两个参数第一个参数表示要在哪个路径下创建管道文件并且这个路径得待上管道文件的名字因为每个文件都有对应的权限所以函数的第二个参数就表示管道文件的权限如果管道文件创建成功了该函数就返回0如果创建失败该函数就直接返回对应的错误码 那么接下来我们就创建一个管道文件出来瞧瞧当前所在的路径如下 那么我们就可以在程序里面通过函数mkfifo来创建管道文件
#includeiostream
#includecerrno
#includestring.h
#includesys/types.h
#includesys/stat.h
using namespace std;
int main()
{umask(0);int nmkfifo(/home/xbb/folder13/name_pipe,0600);if (n 0){coutcreat successendl;}else{cout errno: errno err string: strerror(errno) endl;}return 0;
}那么运行的结果就如下 可以看到程序运行成功之后多出来了一个名为name_pipe的文件并且这个文件是以p为开头那么这个p就表示pipe的意思表示当前文件是管道文件并且使用指令ls -il查看文件inode的时候也可以发现该文件有inode那么这就说明管道文件是一个独立的文件并且当前管道文件的大小为0表示当前文件里面没有任何的数据然后使用下面的指令我们可以往屏幕上面不停地输出数据cnt0; while :; do echo hello world- $cnt; let cnt; sleep 1;done 那么这里我们就可以使用重定向将原本输出到屏幕的数据输出到管道文件里面 运行当前的指令就会不停地往管道里面输入数据但是我们再创建一个进程不停地查看的管道文件的大小时便会发现管道文件的大小没有发生任何变化 可是虽然文件的大小没有发生任何的变化但是当我们使用cat指令输出文件的内容时便又会发现屏幕中打印了我们输入到文件里面的内容 那么这就是管道文件的特性那么接下来我们来看看命名管道的原理。
命名管道的原理
当我们在操作系统中打开一个文件操作系统会创建一个struct file对象该对象里面含有缓冲区和文件有广的操作方法然后进程中的PCB中就会有一个指针指向一个名为file_struct的结构体结构体中存在一个指针数组数组的每个元素就指向不同文件的struct file对象 但是这里存在一个问题如果多个进程打开同一个文件那操作系统会为这个文件创建多个struct file对象吗答案是不会的即使多个进程都打开了同一个文件操作系统也只会创建一个struct file对象所以这就会导致多个进程共用一个struct file如果多个进程共用一个struct file的话那这不就是让多个进程看到同一份资源嘛所以这个strcut file就相当于是一个管道只不过该管道文件的strcut file不会将内部缓冲区的数据刷新到磁盘中的文件里面struct file对象中的数据都是内存级被写入和读取那命名管道是如何做到让不同的进程看到同一份资源的呢答案是让不同的进程打开指定名称路径文件名的同一个文件路径文件名唯一确定的文件之所以叫命名管道是因为该管道是通过文件名的方式来看到同一份资源而匿名管道是父子进程通过继承的方式来确定唯一性并不通过文件名所以将其称之为匿名管道。
命名管道的通信
函数mkfifo可以在程序里面创建命名管道既然有创建那么同样的道理就有对应的函数来删除管道文件unlink函数就可以用来删除创建的管道文件该函数的声明如下 函数内的参数表示要删除的管道文件如果删除成功就返回0删除失败就返回对应的错误码 那么这里我们就可以使用这两个函数来实现进程之间的通信首先创建一个文件这个文件里面就包含两个函数一个函数用来创建管道文件一个函数用来删除管道文件
#includeiostream
#includecerrno
#includestring.h
#includesys/types.h
#includesys/stat.h
using namespace std;
#define PIPE_PATH /home/xbb/folder13/name_pipe
bool createFifo(const string path)
{}void removeFifo(string path)
{}根绝前面的经验我们可以很容易得实现createFifo函数当mkfifo函数返回的值等于0的话就返回true函数的返回值为非0的话就返回false
bool createFifo(const string path)
{umask(0);int nmkfifo(path.c_str(),0600);if(n0){return true;}else{cout errno: errno err string: strerror(errno) endl;return false;}
}同样的道理removeFifo函数里面就是调用unlink函数来进行删除那么这里我们就用assert函数来进行判断文件是否删除成功那这里的代码如下
void removeFifo(const string path)
{int nunlink(path.c_str()); assert(n0);(void)n;
}那么这就是comm.hpp文件的内容接下来我们还要创建server.cc文件和client.cc文件server.cc文件负责从管道里面读取数据client.cc文件就负责从管道里面写入数据因为server.cc文件是读端所以我们就让他来决定管道的创建和删除那么在这个server.cc文件里面首先使用comm.hpp中的creatFifo函数创建管道然后使用assert判断一下创建是否成功创建成功之后就使用open函数以读的方式打开该管道文件然后就得到这个函数的读端的下标
#includecomm.hpp
int main()
{int r createFifo(PIPE_PATH);assert(r);(void)r;int rfdopen(PIPE_PATH, O_RDONLY);cout开始读取endl;if(rfd0){exit(1);}return 0;
}走到这里我们的管道文件就在当前进程顺利的创建并且打开了那么这时我们就可以创建一个while循环不停地往管道里面读取信息因为读取的信息要放到一个地方进行存储所以在循环之前我们还得穿件一个数组用来充当缓冲区那么在循环里面就可以使用read函数从下标为rfd的文件里面读取数据将读取的数据放到缓冲区里面因为读取数据的时候可能会出现结束或者出错的情况所以这里还得创建一个变量用来记录read函数的返回值那么这里的代码如下
#includecomm.hpp
int main()
{int r createFifo(PIPE_PATH);assert(r);(void)r;int rfdopen(PIPE_PATH, O_RDONLY);cout开始读取endl;if(rfd0){exit(1);}char buffer[1024]{0};while(true){ssize_t s read(rfd, buffer, sizeof(buffer)-1);}return 0;
}然后就使用if else语句对size的值进行判断如果size的值大于0就表示当前的读取是正确的我们直接输出buffer里面的值如果size的值等于0就表示当前的读取结束了直接使用break结束while循环如果sizede值小于0就表示当前的读取出现了错误那么我们就打印一下错误码看看哪里出现了问题并使用break结束循环循环结束之后我们就关闭当前打开的管道文件并且使用removeFifo函数删除管道文件那么这里的代码如下
#includecomm.hpp
int main()
{int r createFifo(PATH);assert(r);(void)r;int rfdopen(PATH, O_RDONLY);cout开始读取endl;if(rfd0){exif(1);}char buffer[1024]{0};while(true){ssize_t s read(rfd, buffer, sizeof(buffer)-1);if(s 0){buffer[s] 0;std::cout client-server# buffer std::endl;}else if(s 0){std::cout client quit, me too! std::endl;break;}else{std::cout err string: strerror(errno) std::endl;break;}}close(rfd);// sleep(10);removeFifo(NAMED_PIPE);return 0;
}那么这是server.cc文件的内容那么对于client.cc文件也是同样的道理首先以写的方式打开管道文件然后进行判断再创建一个缓冲区将想要写入管道的信息先写入到缓冲区里再使用write函数将缓冲区的内容放到写入到管道里面然后根据write函数的返回值来判断当前的写入是否成功因为要多次写入所以这里也得添加while循环来进行循环写入
#includecomm.hpp
int main()
{int Wfdopen(PIPE_PATH, O_WRONLY);if(Wfd 0) exit(1);char buffer[1024];coutclient sayendl;while(true){fgets(buffer, sizeof(buffer), stdin);if(strlen(buffer) 0) {//将末尾的/n去掉buffer[strlen(buffer)-1] 0;}ssize_t n write(Wfd, buffer, strlen(buffer));assert(n strlen(buffer));(void)n;}close(Wfd);return 0;
}此文件写完之后我们就可以来完成makefile文件首先该功能的运行需要让两个文件都生成可执行程序所以这里就将指令较为all该指令需要client和server生成可执行程序
.PHONY:
all: client server但是当前路径下并没有可执行程序所以我们还得添加两个可执行程序对应的实现方法和依赖文件
.PHONY:
all: client serverclient:client.ccg -o $ $^ -stdc11 -g
server:server.ccg -o $ $^ -stdc11 -g然后就是删除指令该指令将生成的两个可执行程序删除就行那么makefile的全部内容如下
.PHONY:
all: client serverclient:client.ccg -o $ $^ -stdc11 -g
server:server.ccg -o $ $^ -stdc11 -g.PHONY:
clean:rm -f client server那么接下来我们就可以进行测试首先使用make指令生成两个可执行程序 然后先打开server再打开client程序,然后就可以看到这样的现象 因为写端没有打开所以server一直阻塞在open函数那里当我们运行client程序之后就可以看到server进程打印出来了内容 然后我们往client进程里面输入内容然后便可以看到输入导client里面的内容输出到server这里 那么这就是命名管道的通信。