管道:
一个进程输出数据到另一个进程数据输入的通道。(半双工通信:同一时间,只能一端读另一端写,因为只有一条信道)
有名管道(命令管道):
在磁盘上会存在一个管道文件标识,但管道文件不占用磁盘block空间,数据会缓存在内存上。
可应用于同一台主机上的有权限访问的任意n个进程间通讯。(必须有一对读写进程)
有名管道使用:
创建管道文件:
命令 mkfifo 文件名
函数:int mkfifo(const char * pathname, int mode);
打开:open();write(); read(); close();
创建管道文件:
注意:
必须有一对读-写,只读或只写则会阻塞。
如果所有的读端关闭,则写端也会退出,反之亦然。
读写的次数没有直接联系。
如果写端保持但没有写数据(管道文件没有数据),读端阻塞。当写端将内存写满时,则写端阻塞。
一旦使用mkfifo创建了一个FIFO,就可以使用open打开它,常见的文件I/O函数都可用于fifo。如:close、read、write、unlink等。
FIFO严格遵循先进先出(first in first out),对管道及FIFO的读总是从开始处返回数据,对它们的写则把数据添加到末尾。它们不支持诸如lseek()等文件定位操作。
//进行1,写操作
int fd = open("my_fifo", O_WRONLY);
char send[100] = "Hello Mike";
write(fd, send, strlen(send));
//进程2,读操作
int fd = open("my_fifo", O_RDONLY);//等着只写
char recv[100] = { 0 };
//读数据,命名管道没数据时会阻塞,有数据时就取出来
read(fd, recv, sizeof(recv));
printf("read from my_fifo buf=[%s]\n", recv);
无名管道(仅限父子进程):
没有管道文件标识,借助父子进程之间共享fork之前打开的文件描述符,其数据内容也是在内存上缓存。(一端写一端读)
无名管道的使用:父子进程间通讯
创建&打开: int 匹配(int fds[2]); 创建无名管道并打开,使得fds[0]为读端,fds[1]为写端;
注意:
父子进程必须关闭一对读写,并且不能是同一个进程关闭读写;
逻辑保持管道的半双工通信,防止一端关闭对应的读或写,而另一端无法感知;
#include <unistd.h>
int pipe(int pipefd[2]);
功能:创建无名管道。参数:
pipefd : 为 int 型数组的首地址,其存放了管道的文件描述符 pipefd[0]、pipefd[1]。
当一个管道建立时,它会创建两个文件描述符 fd[0] 和 fd[1]。其中 fd[0] 固定用于读管道,而 fd[1] 固定用于写管道。一般文件 I/O的函数都可以用来操作管道(lseek() 除外)。返回值:
成功:0
失败:-1
下面我们写这个一个例子,子进程通过无名管道给父进程传递一个字符串数据:
int main()
{
int fd_pipe[2] = { 0 };
pid_t pid;
if (pipe(fd_pipe) < 0)
{// 创建管道
perror("pipe");
}
pid = fork(); // 创建进程
if (pid == 0)
{ // 子进程
char buf[] = "I am mike";
// 往管道写端写数据
write(fd_pipe[1], buf, strlen(buf));
_exit(0);
}
else if (pid > 0)
{// 父进程
wait(NULL); // 等待子进程结束,回收其资源
char str[50] = { 0 };
// 从管道里读数据
read(fd_pipe[0], str, sizeof(str));
printf("str=[%s]\n", str); // 打印数据
}
return 0;
}