电子商务网站建设的知识点,怎么才能创建网站,公众号设计平台,cnc强力磁盘 东莞网站建设目录 前言概念命名管道的创建命名管道特性 命名管道通信建立连接资源处理 Client Server通信总结 前言
上一篇文章介绍匿名管道的进程间通信只适合在具有血缘关系的进程间进行通信#xff0c;但是如果我们想让两个不相关的进程实现通信#xff0c;使用匿名管道显… 目录 前言概念命名管道的创建命名管道特性 命名管道通信建立连接资源处理 Client Server通信总结 前言
上一篇文章介绍匿名管道的进程间通信只适合在具有血缘关系的进程间进行通信但是如果我们想让两个不相关的进程实现通信使用匿名管道显然已经不太合适这时候就可以使用另一种方案来实现让不同的进程间进行通信这就是这篇文章要介绍的——命名管道。
概念
命名管道Named Pipes也称为FIFOFirst In, First Out是一种进程间通信的机制。它允许不相关的进程在一个系统中通过文件系统来进行通信。 命名管道的创建
命名管道的创建可以使用命令行工具如mkfifo命令或者在编程语言中的调用系统调用接口如mkfifo函数来创建命名管道。与匿名管道一样命名管道也存在于内存中命名管道是一种特殊类型的文件类似于普通管道。数据通过命名管道传输时不会写入磁盘而是在内存中进行传递。命名管道允许多个进程通过使用相同的管道名称进行通信而不仅仅是两个进程之间的通信。与普通管道一样命名管道中的数据也是临时存储在内存中的。
在命令行中可以直接使用命令mkfifo [pipename]来创建我们需要的命名管道文件。 或者可以使用系统调用接口int mkfifo(const char *pathname, mode_t mode)来创建所需要的管道文件如下代码。
#include iostream
#include sys/types.h
#include sys/stat.h
#include string.h
#include errno.h
int main()
{umask(0);int ret mkfifo(namepipe, 0666);if (ret -1){std::cout errno : strerror(errno) std::endl;}else{std::cout create success! std::endl;}return 0;
}因为命名管道在创建后也是一种文件所以在使用mkfifo系统调用接口时需要注意给定权限。文件最终的权限为mode ~umask因此在创建之前我们可以先将umask置0。另外使用mkfifo创建命名管道如果成功则返回0失败返回-1并设置错误码所以在创建时可以接收返回值做差错处理。 命名管道特性
命名管道与匿名管道类似允许两个或多个进程通过读取和写入管道文件来进行通信。一个进程可以将数据写入管道而另一个进程可以从管道中读取这些数据。也是一种半双工通信数据按照写入的顺序以字节流的形式读取。如果没有进程打开管道的另一端进行读取写入进程可能会被阻塞直到有其他进程来读取数据。同样如果没有进程写入管道尝试读取管道的进程也会被阻塞。命名管道的声明周期是持久的直到被明确删除为止。命名管道不适用于网络通信它仅用于本地进程之间的通信。
命名管道通信
建立连接
使用命名管道通信前提还是让相互独立的进程能看到同一份资源对同一份资源进行操作。所以在命名管道通信之前要先建立链接建立链接第一步就是创建命名管道然后在打开命名管道。为了能让不同进程能对同一个管道文件进行操作因此应该约定好让一个进程在某个路径下创建好一个命名管道其余进程就可以直接打开这个路径下的命名管道这样就可以让几个进程先建立好链接。
资源处理
因为命名管道生命周期不随进程一旦创建后如果不是人为删除就会一直存在因此在通信完毕之后除了关闭相应的文件描述符还需要将没有用的管道文件进行删除。在命令行上可以使用rm命令在程序里面可以使用unlink系统调用接口函数进行删除。 unlink是一个系统调用函数用于删除文件系统中的文件。它可以删除普通文件、符号链接和命名管道等文件类型。当你调用unlink函数来删除一个文件时它会从文件系统中删除该文件的目录项directory entry并释放该文件占用的磁盘空间。文件的实际数据在删除后将不再可用。但是如果有其他进程仍然打开了该文件那么文件仍然存在只是无法通过文件名访问。只有当所有对该文件的打开引用都关闭后文件空间才会被完全释放。需要注意的是unlink函数只删除文件的目录项而不会对打开的文件描述符产生影响。这意味着即使使用unlink删除了文件仍然可以通过已打开的文件描述符继续访问和操作文件的内容直到关闭文件描述符。使用unlink函数删除文件是一个不可逆的操作请谨慎使用确保你真正想要删除的是该文件。 Client Server通信
万事俱备只欠东风。在有了上述的内容储备后就可以简单的写一份Client和Server两进程的简单通信了。
可以设计一个这样的程序让Server进程创建一个命名管道并以只读的方式打开然后循环的读取内容。让Client进程直接以只写的方式打开命名管道循环的将数据写入到命名管道中。当Server进程检测到Client进程退出时Server进程关闭相应的文件描述符并删除命名管道。为了更好的测试可以将程序设计为交互式的当我们输入quit时Client结束写入跳出循环然后关闭文件描述符退出Server进程在检测到Client进程退出后再将管道里数据读取完毕后也跳出循环结束读取关闭文件描述符后删除命名管道。这样我们就可以写出如下代码
//comm.hpp
#include iostream
#include string
#include sys/types.h
#include sys/stat.h
#include cstring
#include errno.h
#include fcntl.h
#include unistd.h
#define NUM 1024mode_t mode 0666;
const std::string fileName ./fifo;//Server.cc
#include comm.hppint main()
{umask(0);// 创建命名管道int ret mkfifo(fileName.c_str(), mode);if (ret -1){std::cout errno : strerror(errno) std::endl;exit(-1);}std::cout create namepipe success std::endl;// 打开命名管道int fd open(fileName.c_str(), O_RDONLY);if (fd 0){std::cout errno : strerror(errno) std::endl;exit(-1);}// 开始写入while (1){char buffer[NUM];int n read(fd, buffer, sizeof(buffer));if (n 0){buffer[n] \0;std::cout client # buffer std::endl;}else if (n 0){std::cout communication finish std::endl;break;}else{std::cout errno : strerror(errno) std::endl;break;}}close(fd);unlink(fileName.c_str());return 0;
}//Client.cc
#include comm.hpp
#include iostream
bool check(const char* s)
{std::string str;while(*s ! \n){str *s;s;}return str ! quit;
}int main()
{// 打开命名管道int fd open(fileName.c_str(), O_WRONLY);if (fd 0){std::cout errno : strerror(errno) std::endl;exit(-1);}// 写入内容char buffer[NUM];std::cout Input : ;char* ret fgets(buffer, NUM, stdin);while (check(ret)){buffer[strlen(buffer) - 1] \0;write(fd, buffer, strlen(buffer));std::cout Input : ;ret fgets(buffer, NUM, stdin);}close(fd);return 0;
}总结
管道是一种在进程间进行通信的机制。它可以用于在一个进程中将输出连接到另一个进程的输入从而实现它们之间的数据传输。无论是命名管道还是匿名管道他们都属于管道通信并且都具有如下的几种特性 单向通信管道是单向的分为读端和写端。写入端将数据写入管道读取端从管道中读取数据。数据在管道中按先进先出FIFO的顺序传输。 匿名管道和命名管道管道可以是匿名的也可以是命名的。匿名管道只能在具有亲缘关系的进程之间使用而命名管道可以用于无关进程之间的通信。 进程间通信管道通信通常用于父子进程或者兄弟进程之间的通信。父进程创建管道并将其的写端传递给子进程子进程通过读取管道来接收父进程发送的数据。 有限的容量管道有一个有限的容量通常是操作系统内核中的一个缓冲区。一旦管道被填满进一步的写入操作将会阻塞直到有足够的空间来容纳数据。 阻塞和非阻塞操作管道的读取和写入操作可以是阻塞的或非阻塞的。阻塞操作将会一直等待直到数据可用或空间可用而非阻塞操作将立即返回无论是否有数据可用或空间可用。 临时性管道中的数据是临时的一旦相关进程关闭了管道的读写端管道中的数据将被销毁无法再被读取。这是因为管道的数据存储在内核的缓冲区中而不是保存在文件系统中。
管道是一种简单而有效的进程间通信机制但它也有一些限制。例如它只支持单向通信数据传输是基于字节流而不是消息的且容量有限。如果需要更复杂的通信需求可以考虑其他的进程间通信方式如命名管道、消息队列、共享内存等。
最后码文不易如果觉得文章对你有帮助的话就点一个呗。