参考文章:https://blog.csdn.net/bit_clearoff/article/details/55105816
管道是进程间通信的方式之一,是在进程之间建立一个实现数据流通的通道,用来缓存要传输的数据。
每个管道有两个文件描述符,写和读。
例:父子进程通信,关闭无关的文件描述符,子->父,子关闭读,父关闭写。
管道特点:
1.管道没有名字。
2.管道是半双工的,数据单向流动,双向通信需要两个管道。
3.只能拥有有亲属关系的进程之间。
4.单独构成文件系统,并且只存在内存中。
5.缓冲区大小有限。
6.数据的写入和读出:一个进程写入的从管道另一边读出,写入在管道末尾,读出在缓冲区头部。
7.管道传送的是无格式字节流。
管道创建
void pipe_init()
{
/*
通过pipe创建一个管道,参数是一个int型pipefd[2],分别代表读和写。
成功返回0,反之-1。
*/
int fd[2];
char readbuffer[20];
char writebuffer[]="hello world";
int temp=pipe(fd);
if(temp<0)
{
cout<<"pipe creat error"<<endl;
exit(0);
}
write(fd[1], writebuffer, sizeof(writebuffer));//管道写入数据
read(fd[0], readbuffer, sizeof(writebuffer));// 读出 size和write一样
cout<<"管道读出的数据:"<<readbuffer<<endl;//输出读到的数据
cout<<"管道的读文件符fd[0]:"<<fd[0]<<" 管道的写文件符fd[0]:"<<fd[1]<<endl;
//结束时要关闭文件描述符
close(fd[0]);
close(fd[1]);
}
父子进程之间通信
(不知道为啥必须在if里面写fork 如果在外面创建pid read读区会出错误)
void pid_pipe1()//在父子进程中进行管道通信 父进程读 子进程写
{
int fd[2];
//char readbuffer[20];
//char writebuffer[]="helloworld";
pid_t pid;
//pid=fork();
int pe=pipe(fd);
if(pe<0)
{
cout<<"pipe failed"<<endl;
exit(1);
}
if(fork()==0)//child 不知道为啥必须在if里面写fork 如果在外面创建pid read读区会出错误
{
char writebuffer[12]="hello world";
close(fd[0]);//子进程写操作 把读关了
write(fd[1], writebuffer, sizeof(writebuffer));//管道写入数据
//write(fd[1], &writebuffer, 1);//管道写入数据
}
else//father
{
sleep(1);
close(fd[1]);//父进程写操作 把写关了
//char readbuffer[20];
char readbuffer[12];
read(fd[0], readbuffer, 12);// 读出 size和write一样
cout<<"父进程中,管道读出的数据:"<<(readbuffer)<<endl;//输出读到的数据
//printf("%s",readbuffer);
}
exit(0);
}
Linux的命名管道
命名管道和管道一样,都是实实在在的文件,但两者的区别在于,命名管道又一个路径名与之关联。管道的文件是不公开的,管道通信只是存在于有亲属关系的进程之中,但是和创建命名管道的进程没有亲属关系的进程,只要可以访问路径,两个进程就可以实现通信。
命名管道的工作方式
1 命名管道由shell创建,将数据从一条管道传递到另一条,无需创建中间临时文件。
2 用于客户进程和服务进程的应用程序,在客户进程和服务器进程之间传递数据。
ps:由于命名管道是文件格式,同一个名字的文件创建成功之后就不能再创建了。
void fun1(int argc, const char * argv[])//使用mkfifo函数创建命名管道
{
mode_t mode=0755;//文件权限设置
if(argc!=2)
{
// cout<<"请输入正确的文件参数"<<endl;
//exit(0);
}
//成功返回0 反之返回-1 第一个参数是命名管道的文件路径名字
if(mkfifo("mingmingguandao", mode)==0)
{
cout<<"命名管道创建成功"<<endl;
//cout<<"创建失败"<<endl;
//exit(1);
}
else
{
cout<<"创建失败"<<endl;
exit(1);
}
}
创建失败的原因是已经创建成功,文件已经存在。
匿名管道(普通管道)完整程序和参考代码
//
// main.cpp
// Linux进程同步-管道和IPC
//
// Created by 蓝猫 on 2018/11/8.
// Copyright © 2018年 蓝猫. All rights reserved.
//
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
using namespace std;
/*
管道是进程间通信的方式之一,是在进程之间建立一个实现数据流通的通道,用来缓存要传输的数据。
每个管道有两个文件描述符,写和读。
例:父子进程通信,关闭无关的文件描述符,子->父,子关闭读,父关闭写。
管道特点:
1.管道没有名字。
2.管道是半双工的,数据单向流动,双向通信需要两个管道。
3.只能拥有有亲属关系的进程之间。
4.单独构成文件系统,并且只存在内存中。
5.缓冲区大小有限。
6.数据的写入和读出:一个进程写入的从管道另一边读出,写入在管道末尾,读出在缓冲区头部。
7.管道传送的是无格式字节流。
*/
void pipe_init()
{
/*
通过pipe创建一个管道,参数是一个int型pipefd[2],分别代表读和写。
成功返回0,反之-1。
*/
int fd[2];
char readbuffer[20];
char writebuffer[]="hello world";
int temp=pipe(fd);
if(temp<0)
{
cout<<"pipe creat error"<<endl;
exit(0);
}
write(fd[1], writebuffer, sizeof(writebuffer));//管道写入数据
read(fd[0], readbuffer, sizeof(writebuffer));// 读出 size和write一样
cout<<"管道读出的数据:"<<readbuffer<<endl;//输出读到的数据
cout<<"管道的读文件符fd[0]:"<<fd[0]<<" 管道的写文件符fd[0]:"<<fd[1]<<endl;
//结束时要关闭文件描述符
close(fd[0]);
close(fd[1]);
}
void pid_pipe1()//在父子进程中进行管道通信 父进程读 子进程写
{
int fd[2];
//char readbuffer[20];
//char writebuffer[]="helloworld";
pid_t pid;
//pid=fork();
int pe=pipe(fd);
if(pe<0)
{
cout<<"pipe failed"<<endl;
exit(1);
}
if(fork()==0)//child
{
char writebuffer[12]="hello world";
close(fd[0]);//子进程写操作 把读关了
write(fd[1], writebuffer, sizeof(writebuffer));//管道写入数据
//write(fd[1], &writebuffer, 1);//管道写入数据
}
else//father
{
sleep(1);
close(fd[1]);//父进程写操作 把写关了
//char readbuffer[20];
char readbuffer[12];
read(fd[0], readbuffer, 12);// 读出 size和write一样
cout<<"父进程中,管道读出的数据:"<<(readbuffer)<<endl;//输出读到的数据
//printf("%s",readbuffer);
}
exit(0);
}
int fun1()
{
int filedes[2];
//pid_t pid;
//pid=fork();
char buf[10];
char out[10];
pipe(filedes);
if(fork() ==0)
{
close(filedes[0]);//子进程写操作 把读关了
sprintf(buf,"%s","ab");
write(filedes[1],buf,sizeof(buf));
}
else
{
close(filedes[1]);//子进程写操作 把读关了
read(filedes[0],out,sizeof(buf));
printf("%s\n",out);
}
return 0;
}
int fun2()
{
//create pipe
int fd[2]={0,0};
if(pipe(fd)!=0){
//create false
perror("pipe");
exit(1);
}
// pipe create success
pid_t id=fork();
if(id==0){
//child -->write fd[1]
printf("Child\n");
sleep(2);
const char* msg="Hello,leap\n";
close(fd[0]);
int count=3;
while(count--){
ssize_t size=write(fd[1],msg,strlen(msg));
printf("size:%d\n",size);
//if(count--){
// sleep(1);
//}
sleep(1);
printf("child is writing...\n");
}
close(fd[1]);
exit(0);
}
else{
//father -->read fd[0]
printf("Father\n");
sleep(2);
close(fd[1]);
char buf[1024];
int count=3;
while(1){
ssize_t Len=read(fd[0],buf,1024);
//printf("Len::%d\n",Len);
printf("Father is reading...\n");
if(Len>0){
//read success
buf[Len]='\0';
printf("child say:%s",buf);
}
else if(Len==0){
//read end of file
printf("Read the end of pipe\n");
break;
}
else{
perror("read");
exit(1);
}
}
close(fd[0]);
int status=0;
pid_t _pid=waitpid(id,&status,0);
if(_pid==id){
printf("Wait success for child\n");
printf("Exit code:%d,Exit signal:%d\n",(status>>8)&0xff,status&0xff);
}
else{
perror("wait");
}
exit(0);
}
return 0;
}
int main(int argc, const char * argv[])
{
pid_pipe1();
//fun2();
return 0;
}