文章目录
序言
让无血缘关系的进程间通信
(所谓血缘关系就是上篇blog所讲的父子进程,子进程的子进程,父进程的两个子进程之间的关系等这种即为血缘关系).
linux中命名管道叫做fifo
利用指令创建
演示结果:
输出信息,实现通信
本来输出到次终端的信息,到了另一个终端
循环实现
echo和cat两个无相关的进程实现了通信
实现上述操作的时候再开一个终端发现,管道的大小一直是0
这个管道是创建出来的磁盘级的一个符号,实际通信不会向磁盘刷新,也没必要
命名管道本质
现在存在一个命名管道,A,B两个进程分别用读和写的方式打开,他俩看到了一份公共的资源
为什么能看到同一份资源?
路径具有唯一性,使用路径+文件名的方式,来唯一的让不同的进程看到同一份资源
现在A进程的实际执行情况是,打开了这个
文件,也有对应的文件缓冲区指向这个文件
B进程打开就不会再重新加载这个文件到
缓冲区之类的
但毕竟是不同的进程打开
他们各自进程指向的文件中的位置不一样
现在这个文件不是普通文件,而是mkfifo创建的管道文件,
所以此时文件不会指向对应的缓冲区,而是直接让两个进程在缓冲区进行交流
代码创建管道实现通信
makefifo创建命名管道文件
利用client和server两个进程来查看
bash
.PHONY:all
all:server client
server:server.cc
g++ -o $@ $^ -std=c++11
client:client.cc
g++ -o $@ $^ -std=c++11
.PHONY:clean
clean:
rm -f server client .fifo
通过代码在server创建管道
创建管道的发送服务端:
创建管道,创建失败返回错误信息
errno:向显示器输出错误信息(stderr)
strerror:strerror(errno): 接受错误码作为参数,并返回对应错误码的字符串描述。
make生成
然后运行这个server服务创建管道:
read函数从指定文件中读取一个长度放回buf中,然回值是读取到的字符串的长度
读端代码(服务端)
写端代码(客户端)
最终两个.cc文件汇聚到一个.h内
为了让他们看到同一份资源
进行实践时,首先一定要打开读端,以前说过写端关闭,读端一直读,读端会读到文件的结尾,表示为0,即这时read的返回值为0.但是这里不会读到0,因为就要考虑这种情况,读端一直打开,写端没有时,会进行堵塞等待(个人猜测时mkfifo函数的功能导致阻塞),一定要先./server 然后再./client,再在./client端输入信息
这段代码是按下回车进行输出,通过这个例子可以通过某些函数接口实现实时信息输出(即按什么立刻显示什么,不用按回车)
上述代码不合理的地方,当fifo存在时会直接报错退出,现在实现不存在就创建,存在就不创建然后执行后续代码
完整代码
comm.h
cpp
#include<iostream>
#include<unistd.h>
#include<vector>
#include<cstring>
#include<cerrno>
#include <sys/types.h>
#include <sys/stat.h>
#include<fcntl.h>
#define FIFONAME ".fifo"//生成的文件默认为隐藏文件
using namespace std;
server.cc
cpp
#include "comm.h"
bool MakeFifo()
{
int n = mkfifo(FIFONAME, 0666);//创建管道
if(n < 0)
{
cerr << "errno:" << errno << ", errstring: " << strerror(errno) << endl;
return false;
}
return true;
}
int main()
{
Strat:
int rfd = open(FIFONAME,O_RDONLY);//打开管道
if(rfd < 0)
{
if(MakeFifo()) goto Strat;
cerr << "errno:" << errno << ", errstring: " << strerror(errno) << endl;
return 1;
}
char buf[1024];
while(true)//读端
{
ssize_t s = read(rfd,buf,sizeof(buf)-1);
if(s > 0)
{
buf[s] = 0;
cout << "Client say# " << buf << endl;
}
else if(s == 0)
{
cout << "client quit,server quit too!" << endl;
break;
}
}
close(rfd);
return 0;
}
client.cc
cpp
#include"comm.h"
int main()
{
int wfd = open(FIFONAME,O_WRONLY);//打开管道文件
if(wfd < 0)
{
cerr << "errno:" << errno << ", errstring: " << strerror(errno) << endl;
return 1;
}
//将信息写入管道
string message;
while(true)
{
cout << "Please Enter# " << endl;
getline(cin,message);//从键盘获取message
//将message写入管道
ssize_t s = write(wfd,message.c_str(),message.size());
if(s < 0)
{
cerr << "errno:" << errno << ", errstring: " << strerror(errno) << endl;
break;
}
}
close(wfd);
return 0;
}
本期blog到此结束,有用请三连~~
欢迎随时交流~~