管道包括无名管道和有名管道两种,前者用于父进程和子进程间的通信后者用于运行于同一台机,器上的任意两个进程间的通信。
管道所传送的是无格式字节流,这就要求管道的读出方和写入方必须事先约定好数据的格式,比如多少字节算作一个消息(或命令、或记录)等等
无名管道
1、 数据自己读不能自己写。
2、 数据一旦被读走,便不在管道中存在,不可反复读取。
3、 由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。
4、只能在有公共祖先的进程间使用管道。
5、管道不是普通的文件,不属于某个文件系统,其只存在于内存中。
6、从管道读数据是一次性操作,数据一旦被读走,它就从管道中被抛弃,释放空间以便写更多的数据。
7、默认的情况下,从管道中读写数据,最主要的特点就是阻塞问题(这一特点应该记住),当管道里没有数据,另一个进程默认用 read() 函数从管道中读数据是阻塞的。
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define INPUT 0
#define OUTPUT 1
int main()
{
int fd[2];
pid_t pid;
char buf[256];
int ret_cnt;
// 创建无名管道
// 返回两个文件描述符,fd[0]用于读,fd[1]用于写
pipe(fd);
if((pid = fork()) < 0)
{
printf("Error in fork\n");
exit(1);
}
if(pid > 0) // 父进程
{
wait(0);
printf("parent\n");
ret_cnt = read(fd[INPUT], buf, sizeof(buf));
printf("%d bytes of data recevied from child\n", ret_cnt);
exit(0);
}
else // 子进程
{
printf("child\n");
write(fd[OUTPUT], "test data", strlen("test data"));
}
return 0;
}
有名管道
有名管道(named pipe或FIFO)不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中。这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信(能够访问该路径的进程以及FIFO的创建进程之间),因此,通过FIFO不相关的进程也能交换数据。值得注意的是,FIFO严格遵循先进先出(first in first out),对管道及FIFO的读总是从开始处返回数据,对它们的写则把数据添加到末尾。它们不支持诸如lseek()等文件定位操作。
写端
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#define BUF_SIZE PIPE_BUF
int main()
{
char buf[BUF_SIZE+1] = "Hello word!";
if(access("/tmp/fifo.txt", F_OK) == -1) // 如果不存在
{
// 创建 有名管道
// int mkfifo( const char *pathname, mode_t mode);
// pathname: 普通的路径名,也就是创建后 FIFO 的名字
// mode: 文件的权限,与打开普通文件的 open() 函数中的 mode 参数相同
// 返回值:成功:0; 失败:如果文件已经存在,则会出错且返回 -1
int rt = mkfifo("/tmp/fifo.txt", 0777);
if(rt != 0)
{
fprintf(stderr, "Could not create fifo %s\n", "/tmp/fifo.txt");
exit(EXIT_FAILURE);
}
}
printf("Process %d opening FIFO O_WRONLY\n", getpid());
int fd = open("/tmp/fifo.txt", O_WRONLY); // 打开
int bytes = 0;
if(fd != -1)
{
bytes = write(fd, buf, strlen(buf)); // 写入
if(bytes == -1)
{
fprintf(stderr, "Write error on pipe\n");
exit(EXIT_FAILURE);
}
close(fd); // 关闭
}
else
{
printf("Open failure\n");
exit(EXIT_FAILURE);
}
printf("Process %d finish, %d bytes had been wroten\n", getpid(), bytes);
return 0;
}
读端
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#define BUF_SIZE PIPE_BUF
int main()
{
char buf[BUF_SIZE+1];
memset(buf, '\0', sizeof(buf));
printf("Precess %d opening FIFO O_RDONLY\n", getpid());
int fd = open("/tmp/fifo.txt", O_RDONLY); // 打开
int bytes = 0;
if(fd != -1)
{
int cnt = 0;
do
{
cnt = read(fd, buf, BUF_SIZE); // 读取
bytes += cnt;
}while(cnt > 0);
close(fd); // 关闭
}
else
{
exit(EXIT_FAILURE);
}
printf("Process %d finished, %d bytes read\n", getpid(), bytes);
return 0;
}
运行写端,运行了读端后,写端才会结束。
运行读端,运行了写端后,读端才会结束。
参考
https://blog.csdn.net/eroswang/article/details/1772350
https://blog.csdn.net/oguro/article/details/53841949
https://blog.csdn.net/tennysonsky/article/details/46315517
https://blog.csdn.net/firefoxbug/article/details/8137762
https://blog.csdn.net/tennysonsky/article/details/46326957