目录
前言
一、有名管道
1、用法
2、管道分类
3、有名管道的创建
4、思考:如何进程a要将键盘获取的数据传递给另一个进程b?
5、有名管道实现进程间通信
二、无名管道
1、无名管道的创建
2、管道操作分为以下步骤
3、无名管道实现进程间通信
前言
进程间通信方法:
(1)管道
(2)信号量
(3)共享内存
(4)消息队列
(5)套接字
一、有名管道
1、用法
- | 命令
- 举例:ps -ef|grep "sleep"
两个进程通信:比如a,b进程,a想管道中写入数据,b读取数据;
2、管道分类
(1)有名管道
(2)无名管道
区别:有名管道可以在任意进程间通信;无名管道主要在父子进程间通信。(重点)
3、有名管道的创建
①命令:mkfifo (属于系统调用)
②打开管道:open()
③读数据:read()
④写数据:write()
⑤关闭管道:close()
4、思考:如何进程a要将键盘获取的数据传递给另一个进程b?
(不能用文件传递),效率太慢。
创建管道之后,它会在内存上分配一块空间,表面上卡把数据写入管道中了,实际上是吧数据写入内存中了。另外一个程序是从内存中读取数据的,所以效率是比较高的。
管道文件的大小永远为0。如下图所示:
5、有名管道实现进程间通信
(1)参考代码:
//a.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<fcntl.h>int main()
{int fd=open("fifi",O_WRONLY);assert(fd!=-1);printf("fd=%d\n",fd);write(fd,"hello",5);close(fd);}//加入循环后:
//c.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<fcntl.h>int main()
{int fd=open("fifi",O_WRONLY);assert(fd!=-1);// printf("fd=%d\n",fd);while(1){printf("input:\n");char buff[128]={0};fgets(buff,128,stdin);if(strncmp(buff,"end",3)==0){break;} write(fd,buff,strlen(buff));}close(fd);}
//b.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<fcntl.h>int main()
{int fd=open("./fifi",O_RDONLY);assert(fd!=-1);printf("fd=%d\n",fd);char buff[128]={0};read(fd,buff,127);printf("read:%s\n",buff);close(fd);}//加入循环后:
//d.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<fcntl.h>int main()
{int fd=open("./fifi",O_RDONLY);assert(fd!=-1);printf("fd=%d\n",fd);while(1){char buff[128]={0};if(read(fd,buff,127)==0){break;}printf("read:%s\n",buff);}close(fd);}
(2)管道的特点
①管道必须读、写进程同时open,否则会阻塞;
- 阻塞的情况:(只有写进程open或只有读进程open)
正确的通信:读写进程同时open(打开两个窗口)
②如果管道中没有数据,那么read就会阻塞。
③管道的写端关闭,读read返回值为0;
④管道打开的时候只读和只写方式,读写方式是未定义的。
⑤管道是半双工的(某一时刻只能选择一个方向)(重点)
通信方式:单工、半双工、全双工。
⑥无论有名还是无名, 写入管道的数据都在内存中。(重点)
⑧管道的读端关闭,写会产生异常(发送信号SIGPIPE)(可以改变信号的响应方式验证一下)。
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<fcntl.h>
#include<signal.h>//发送信号
void fun(int sig)
{printf("sig=%d\n",sig);
}int main()
{signal(SIGPIPE,fun);int fd=open("fifi",O_WRONLY);assert(fd!=-1);// printf("fd=%d\n",fd);while(1){printf("input:\n");char buff[128]={0};fgets(buff,128,stdin);if(strncmp(buff,"end",3)==0){break;} write(fd,buff,strlen(buff));}close(fd);}
二、无名管道
使用pipe创建无名管道,**只能进行父子间的通信;
pipe是一个系统调用
1、无名管道的创建
int pipe(int fds[2]);
//pipe()成功返回0,失败返回-1;
//fds[0]是管道读端的描述符
//fds[1]是管道写端的描述符
2、管道操作分为以下步骤
(1)父进程调用pipe函数开辟管道,得到两个文件描述符指向管道的两端;
(2)父进程用fork创建子进程,那么子进程也有两个文件描述符指向同一管道;
(3)父进程关闭管道文件读端,子进程关闭写端。父进程可以往管道里写数据,子进程可以从管道中读数据,这样就在父子进程之间建立管道,实现进程间通信。
3、无名管道实现进程间通信
参考代码:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>int main()
{int fd[2];assert(pipe(fd)!=-1);pid_t pid=fork();//先open,再fork,父子进程共享打开的文件描述符assert(pid!=-1);if(pid==0){close(fd[1]);char buff[128]={0};read(fd[0],buff,127);printf("child read:%s\n",buff);close(fd[0]);}else{close(fd[0]);write(fd[1],"hello",5);close(fd[1]);}exit(0);
}
如有错误,敬请指正。
您的收藏与点赞都是对我最大的鼓励和支持!