下面是有关进程通信中管道的相关介绍,希望对你有所帮助!
小海编程心语录-CSDN博客
1. 进程通信的基本概念
1.1 概念
进程间通信简称 IPC ,指两个进程之间的通信。 IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、Streams等。其中 Socket和Streams支持不同主机上的两个进程IPC。
1.2 目的
- 数据传输:一个进程需要将它的数据发送给另一个进程。
- 资源共享:多个进程之间共享同样的资源。
- 通知事件:一个进程需要向另一个或一组进程发送消息,通知它们发生了某种事件。
- 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),该控制进程希望能够拦截另一个进程的所有操作,并能够及时知道它的状态改变。
1.3 通信方式
- UNIX IPC: 管道、FIFO、信号
- System V IPC: 信号量、消息队列、共享内存
- Socket IPC: 基于Socket进程间通信
2. 管道
把一个进程连接到另一个进程的数据流称为管道,是一个半双工的通信方式。
管道分为有名管道和无名管道两种,它们的区别是:
无名管道只能在有亲缘关系的进程之间进行通信。
有名管道又称为命名管道,可以在任意两个进程之间进行通信。
2.1 无名管道
//函数原型
#include <unistd.h>
int pipe( int fd[2] );
匿名管道适用于一对一的、具有亲缘关系的进程间的通信
是一个半双工的通信方式,具有固定的读端和写端。
管道可以看做是一种特殊的文件,对管道的读写可以使用普通的read() ,write()函数,但管道不属于任何文件系统的,只存在于内存中。
2.1.1 如何操作无名管道
- 创建 :(pipe函数用来创建无名管道)
- 操作 :(read读;write写) 写是 fd[1],读是 fd[0]
- 关闭操作端口 :(close)
2.1.2 示例代码
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <sys/types.h>
#include <stdlib.h>
int main()
{
//创建无名管道
int fd[2];
pipe(fd);
if(fork() == 0)
{
close(fd[0]); //读关闭
char *buf = "hello world";
write(fd[1], buf, strlen(buf)); //写操作
}
else
{
close(fd[1]); //写关闭
char showbuf[100];
bzero(showbuf, 100); //清空缓冲区
read(fd[0], showbuf, 100); //读操作
printf("txt is :%s\n", showbuf); //打印内容
exit(0);
}
}
代码运行结果
2.2 有名管道
//函数原型
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
// pathname:具名管道的名称
// mode:文件权限模式,例如0666
具名管道通常又被称为FIFO,它是对无名管道的一种改进,其更接近普通文件,有文件名、可以open打开、支持read()/write()等读写操作
Linux在共享文件夹下,创建管道文件是创建不了的,运行结果为空,因此要将执行文件移到非共享文件夹下。因为共享文件夹和Windows是共享的,有些文件windows是没有的。
特性
它可以使互不相关的两个进程实现彼此通信
该管道可以通过路径名来指出,并且在文件系统中是可见的。在建立管道之后,两个进程就可以把它当作普通文件进行读写,使用非常方便。
FIFO严格遵循先进先出原则,对管道及FIFO的读总是从开始处返回数据,对它们的写则把数据添加到末尾。有名管道不支持如Iseek()等文件的定位操作。
2.2.1 如何操作具名管道
- 创建有名管道文件 :(mkfifo即是命令也是函数;mknod也可以创建管道文件)
- 打开有名管道 :(open)
- 读/写 :(read/write)
- 关闭 :(close)
具名管道一旦没有任何读者和写者,系统判定管道处于空闲状态,会释放管道中的所有数据
1.写者
- 创建有名管道文件 mkfifo()
- 打开有名管道 open()
- 创建缓冲区,写内容 buf
- 写操作 write()
- 关闭有名管道 close()
2.读者
- 打开有名管道 open()
- 创建缓冲区,清空缓冲区 buf bzero()
- 读操作,打印 read()
- 关闭有名管道 close()
2.2.2 示例代码
//读者
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
int main()
{
int fd = open("./fifo", O_RDWR); //打开有名管道
char showbuf[100]; //创建缓冲区
bzero(showbuf, 100); //清空缓冲区
read(fd, showbuf, 100); //读
printf("%s\n", showbuf); //打印
close(fd); //关闭
return 0;
}
//写者
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
int main()
{
mkfifo("./fifo", 0666); //创建有名管道文件
int fd = open("./fifo", O_RDWR); //打开有名管道
char *buf = "hello world"; //写
write(fd, buf, strlen(buf));
close(fd); //关闭
return 0;
}
注意:
在Linux在共享文件夹下,创建管道文件是创建不了的,运行结果为空,因此要将执行文件移到非共享文件夹下,这里我把执行文件放到家目录的test文件夹下了。
打开两个终端执行命令,这里可用Ctrl+shift+n快速打开相同路径下的终端
代码运行结果
3. 相关练习
编写两个程序,一个客户端、一个服务器端,服务器端创建并且监视管道,发现如果有数据就把它保存到指定位置,客户端将当前系统时间和自己的PID写入管道
3.1 客户端
//cilent 客户端
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <time.h>
int main()
{
int fd = open("./fifo", O_RDWR); //打开有名管道
char buf[1000]; //创建缓冲区
time_t tim;
while(1)
{
bzero(buf,1000); //清空缓冲区
time(&tim); //时间
sprintf(buf,"[%d]: %s",getpid(),ctime(&tim)); //打印到buf指向的字符串中
write(fd,buf,strlen(buf)); //写操作,在日志文件中写入数据
sleep(2);
}
return 0;
}
3.2 服务器端
//server 服务器端
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
int main()
{
mkfifo("./fifo", 0666); //创建有名管道文件
int logfd = open("./log.txt",O_RDWR | O_CREAT,0777); //创建日志文件
int fd = open("./fifo", O_RDWR); //打开有名管道
char buf[1000]; //创建缓冲区
while(1)
{
bzero(buf,1000); //清空缓冲区
read(fd,buf,1000); //读取缓冲区数据
write(logfd,buf,strlen(buf)); //在日志文件中写入数据
}
return 0;
}
代码运行结果
如果喜欢请不吝给予三连支持!
小海编程心语录-CSDN博客