目录
管道是什么
概念:管道是计算机通信领域设计者,设计出的一种单向通信的方式,linux原生提供管道通信
管道都是单向传输内容的
管道中传输的都是"资源"
管道通信不会将内容刷新到磁盘,是内存级的通信(效率高)
管道是半双工的:
全双工:既可以收又可以发,同时进行
半双工:要么在收要么发
匿名管道
//头文件
#include <unistd.h>
//函数
int pipe(int pipefd[2]);
//返回值
//成功返回0,失败返回-1,会设置错误码到errno中
//参数
//int pipefd[2]
//输出型参数,我们提供一个数组传入,这个数组会被填充两个文件描述符,pipefd[0]是读,pipefd[1]是写
1、分别以读写方式打开同一个文件
2、fork()创建子进程
3、双方进程各自关闭自己不需要的文件描述符
4、进行通信
5、通信结束
#include<iostream>
#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<string.h>
using namespace std;
int main()
{
int pipefd[2]; //创建一个数组,接受文件描述符
if(pipe(pipefd) < 0) //判断管道是否创建成功
{
perror("pipe"); //失败打印pipe,然后退出
return -1;
}
pid_t id = fork(); //创建一个进程
if(id < 0) //判读进程是否创建成功
{
perror("fork"); //失败打印fork,然后退出
return -1;
}
if(id == 0) //我们让子进程进行读取
{
close(pipefd[1]); //关闭写进程
char buff[64];
while(1) //进行通信
{
ssize_t s = read(pipefd[0], buff, sizeof(buff));
if(s > 0)
{
if(strcmp(buff, "q") == 0)
{
cout << "quit" << endl;
break;
}
cout << "parent say: " << buff << endl;
}
else if(s == 0)
{
cout << "eof" << endl;
break;
}
else
{
cout << "read error" << endl;
break;
}
}
close(pipefd[0]); //关闭读进程
}
//父进程进程通信
close(pipefd[0]); //关闭读
if(id > 0)
{
char buff[64];
while(1)
{
cin >> buff;
write(pipefd[1], buff, sizeof(buff));
if(strcmp(buff, "q") == 0)
{
break;
}
}
}
//通信结束
wait(NULL);
close(pipefd[1]); //关闭写
return 0;
}
匿名管道的特点:
管道是用来进行具有血缘关系的进程进行进程间同通信 -- 常用于父子通信
a、写快,读慢,写满就不能写了
b、写慢,读快,管道没有数据的时候,读必须等待
c、写关,读0,表示读到了文件结尾
d、读关,写继续写,os终止写进程
命名管道
为了解决匿名管道只能父子间通信,产生了命名管道
命名管道创建方式
方式一:
mkfifo指令:
mkfifo 管道名 --创建一个命名管道
方式二:
mkfifo函数
//头文件
#include <sys/types.h>
#include <sys/stat.h>
//函数
int mkfifo(const char *pathname, mode_t mode);
//返回值 创建成功返回0,失败返回-1
//参数
//const char *pathname,创建的路径
//mode_t mode,创建权限
命名管道fifo是p标识管道文件
1、分别写一个客户端,一个服务端
2、服务端创建命名管道
3、服务端发送信息,客服端接受信息
4、通信结束,客服端和服务端退出
服务端,server.cpp
#include<iostream>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdio.h>
#include<string.h>
using namespace std;
int main()
{
umask(0000); //将权限掩码设置为0000
if(mkfifo("./fifo", 0666)) //创建命名管道fifo
{
perror("mkfifo");
return -1;
}
int fd = open("./fifo", O_WRONLY); //以写方式打开命名管道
if(fd < 0)
{
perror("open");
return -1;
}
char buff[64];
while(1)
{
cin >> buff;
write(fd, buff, sizeof(buff));
if(strcmp(buff, "q") == 0)
{
cout << "quit" << endl;
break;
}
}
unlink("./fifo"); //删除命名管道
return 0;
}
客服端,client.cpp
#include<iostream>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdio.h>
#include<string.h>
using namespace std;
int main()
{
umask(0000); //将权限掩码设置为0000
if(mkfifo("./fifo", 0666)) //创建命名管道fifo
{
perror("mkfifo");
return -1;
}
int fd = open("./fifo", O_WRONLY); //以写方式打开命名管道
if(fd < 0)
{
perror("open");
return -1;
}
char buff[64];
while(1)
{
cin >> buff;
write(fd, buff, sizeof(buff));
if(strcmp(buff, "q") == 0)
{
cout << "quit" << endl;
break;
}
}
unlink("./fifo"); //删除命名管道
return 0;
}
管道的特点:
1、匿名管道是用来进行具有血缘关系的进程进行进程间同通信 -- 常用于父子通信
2、管道具有通过让进程间协同,提供了访问控制 假如写满,需要等待被读取才能继续写入
3、管道提供的是面向流式的服务 -- 面向字节流 -- 协议
4、管道是基于文件的,文件的生命周期是随进程的,管道的生命周期是随子进程的
5、管道是单向通信的(半双工通信的一种特殊情况)
全双工:既可以收又可以发,同时进行
半双工:要么在收要么发