文章目录
没有血缘关系的进程之间是如何做到通信的?
管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。
如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。
命名管道是一种特殊类型的文件。用命名管道通信。
mkfifo
创建一个命名管道使用mkfifo创建,在自己的工作目录中创建管道,在命令函行上创建,管道文件是以p开头
文件类型是管道文件
不同进程,命名管道级别之间的通信,这样一个进程写一个进程就会读到,就可以实现不同进程之间的通信
命名管道可以从命令行上创建,命令行方法是使用下面这个命令: mkfifo filename
命名管道也可以从程序里创建,相关函数有:int mkfifo(const char *filename,mode_t mode);
创建好管道之后,要让进程之间能过通信,而进程能够通信的本质是看到同一份资源!要让不同进程看到同一个命名管道文件
再打开文件时怎么知道打开的是同一个文件?同一路径下同一个文件名 = 路径+文件名。路径+文件名有唯一性。
不同进程之间通信就是两个启动的程序进行通信,形成两个程序,在程序中用函数创建一个管道文件调用mkfifo函数,而管道文件只需要创建一次就可以了。然后要考虑让两个进程都看见同一个通信信道管道文件。进程要通信先创建管道。两个进程通信一个为服务端一个为客户端,服务端为客户端提供服务,管道由服务端创建,但是在建立管道之后,只是将信道建立好了,服务方不能立即打开文件,因为写方没有向管道文件中写入数据,那么服务端就会阻塞,要等待客户端写入之后服务端才开始打开文件然后读取客户端给服务端发送的数据。
头文件方法实现,建立管道文件和删除管道文件放在了头文件中实现,当建立好管道文件之后两个进程都能拿到,当一个文件刚被建立时有文件权限
comm.hpp
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include <string>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#define FIFO_FILE "./myfifo" //打开文件
#define MODE 0664 //打开文件的之后该文件的权限
using namespace std;
//枚举打开文件
enum
{
FIFO_CREATE_ERR = 1,
FIFO_DELETE_ERR,
FIFO_OPEN_ERR
};
class Init
{
public:
Init()
{
//创建管道文件
int n = mkfifo(FIFO_FILE,MODE);
//管道文件返回值<0则创建管道文件失败
if(n==-1)
{
perror("mkfifo");
exit(FIFO_CREATE_ERR);
}
}
~Init()
{
int m = unlink(FIFO_FILE);
if (m == -1)
{
perror("unlink");
exit(FIFO_DELETE_ERR);
}
}
};
删除管道文件用unlink
servere.cc
服务端,建立通信信道,并且这一端只能读
#include<iostream>
#include"comm.hpp"
int main()
{
Init init;
//创建成功之后就什么都不做
//这个管道文件已经创建成功了,然后要进行通信
//创建管道文件之后,由客户端向管道中写入数据,然后由服务端来解析提供服务
int fd = open(FIFO_FILE,O_RDONLY);// 等待写入方打开之后,自己才会打开文件,向后执行, open 阻塞了!
if(fd<0)
{
perror("open");
exit(FIFO_OPEN_ERR);
}
cout<<"server open file"<<endl;
//通信信道打开之后就开始通信
// 开始通信
while (true)
{
char buffer[1024] = {0};
int x = read(fd, buffer, sizeof(buffer));
if (x > 0)
{
buffer[x] = 0;
cout << "client say# " << buffer << endl;//对于从客户端拿到的数据分析或者打印
}
else if (x == 0)
{
// log(Debug, "client quit, me too!, error string: %s, error code: %d", strerror(errno), errno);
break;
}
else
break;
}
close(fd);
return 0;
}
客户端,向管道文件中写入数据,但是要当服务端将信道建立之后才能往信道中写入数据进行通信
client.cc
#include<iostream>
#include"comm.hpp"
using namespace std;
int main()
{
int fd = open(FIFO_FILE,O_WRONLY);//客户端以写的方式打开这个管道文件
if(fd < 0)
{
perror("open");
exit(FIFO_OPEN_ERR);
}
cout << "client open file done" << endl;
string line;
while(true)
{
cout<<"Please enter@ ";
getline(cin,line);
//客户端向这个管道文件中写入数据,然后让服务端来读取
write(fd,line.c_str(),line.size());
}
close(fd);
return 0;
}
不能先执行客户端
必须先让服务端建立信道
不过服务端建立信道之后要阻塞等待客户端向管道中写入数据,若是客户端不写服务端就一直在等
当将客户端打开之后然后服务端才以读的方式打开这个管道,不过还是要等待客户端写入数据,客户端写入服务端就能读到
当写端关闭读端读到0他也会退出,并且在退出的时候把管道文件给删除,以便下次通信的时候再用。若是管道文件不删除,客户端就能直接打开,并且服务端会显示这个管道文件已经存在不会再建立,此时客户端向这个管道中写入没有进程来读,所有每一次通信完成之后要将管道文件删除!