管道分为有名管道和无名管道。
无名管道:
无名管道是半双工的,就是对于一个管道来讲只能读或者写。就像高速公路一样一条路只能单向行驶。
无名管道,只能在相关的,有亲缘关系的进程使用。例如:一个fork或者exec调用创建的子进程继承了父进程的文件描述符。这时候它就可以和父进程来一起使用无名管道。
创建无名管道的函数:
所需要头文件:#include<unistd.h>
函数原型:int pipe(int fd[2])
函数的传入值:fd[2]:是管道的描述符数组他,在主调函数为数组分配内存,传入数组首地址,间接修改数组的值共主调函数使用。fd[0]代表读,fd[1]代表写。
函数的返回值:失败返回-1,成功返回0
一个简单的无名管道的例子:
/*
* main.c
*
* Created on: 2015-1-29
* Author: hsc
*/
#include <stdio.h>
#include <stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include <string.h>
#include <sys/wait.h>
#include <errno.h>
int main(void)
{
int pipefd[2];
char buf[1024];
pid_t pid;
if(pipe(pipefd) == -1)//创建无名管道
{
printf("%s \n", strerror(errno)); //创建管道失败
return -1;
}
pid = fork();//创建进程
if(pid == -1)
{
printf("%s \n", strerror(errno));//出错的情况
return -1;
}
if(pid == 0)
{
int len;
memset(buf,0,sizeof(buf));
close(pipefd[1]);//close write pipe
while((len=read(pipefd[0],buf,sizeof(buf)))>0)
{
write(STDOUT_FILENO,buf,strlen(buf));
}
close(pipefd[0]);
}
else
{
memset(buf,0,sizeof(buf));
close(pipefd[0]);//close read pipe
strcpy(buf,"hello world !\n");
if(-1 == write(pipefd[1],buf,strlen(buf)))
{
printf("%s \n", strerror(errno));
}
close(pipefd[1]);
waitpid(pid,NULL,0);//等待子进程退出
}
return 0;
}
有名管道(FIFO):
有名管道是持久稳定的,存在于文件系统。
FIFO除了具有无名管道的所有特性外,它还允许无亲缘关系的进程间通信进行数据交换。
可以通过shell 命令建立有名管道
mkfifo [option] name
mkfifo 创建一个名为name的有名管道
例如:
mkfifo fifo
使用cat <fifo 这里<符号是重定向输入表示从管道fifo读取内容。
重新打开一个终端,到同一目录下执行ls -l>fifo。这里>符号是重定向输出表示向道fifo写内容。
在创建管道成功之后,就可以使用open(),read(),write()这些系统调用,就像操作普通文件一样,对于为读而打开的管道,在open()设置为O_RDONLY,同样为写而打开的管道在open()设置为O_WRONLY,与读写普通文件不同是阻塞问题。当然可以在open()函数设置非阻塞标志O_NONBLOCK。这里对于一个管道可以理解为从管道的一头写另一头读。
对于读进程:
1.如果管道是阻塞打开,且当管道内没有数据,则对于读进程来说将一直阻塞到有数据写入。
2.如果管道是非阻塞打开,则不论管道内是否有数据,读进程都会立即执行读的操作。没有数据,则返回0。
对于写进程:
1.如果管道是阻塞打开,且当管道内没有数据,则对于写进程来说将一直阻塞到有数据可以被写入(比如管道满了)。
2.如果管道是非阻塞打开而不能写入全部数据,则读操作进行的部分写入或者调用失败。
值得注意的是:在数据能被传送之前,管道必须被打开在两端(读和写),正常情况下只open一个它会阻塞直到另外一个open。也就是说你先执行写的管道(FIFO)则程序会
阻塞在open()函数这里,直到运行读管道程序open()。
读程序如下:read_fifo.c
/*
* read_fifo.c
*
* Created on: 2015-2-2
* Author: hsc
*/
/*
* main.c
*
* Created on: 2015-2-2
* Author: hsc
*/
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include <sys/stat.h>
#include<unistd.h>
#include <fcntl.h>
#include<errno.h>
#define MYFIFO "myfifo"
#define BUFFSIZE 1024
int main()
{
int fd; //定义文件描述符
char buf[BUFFSIZE]; //定义buf
if(access(MYFIFO,F_OK) == -1) //判断管道文件是否存在
{
if(mkfifo(MYFIFO,0666)== -1) //6表示有读写权限 0666(0表示是八进制 6表示读写) 对于用户、组、其他都对该文件有读写权
{
printf("%s",strerror(errno)); //输出错误原因
return -1;
}
}
fd = open(MYFIFO,O_RDONLY);// 已只读方式打开管道文件
if(fd == -1)
{
printf("%s",strerror(errno));
return -1;
}
memset(buf,0,BUFFSIZE);//buf 清空
if(read(fd,buf,BUFFSIZE) ==-1)// 读管道
{
printf("%s",strerror(errno));
}
else
{
printf("read:%s ",buf);
}
close(fd);//关闭打开管道
return 0;
}
写管道程序:write_fifo.c
/*
* main.c
*
* Created on: 2015-2-2
* Author: hsc
*/
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include <sys/stat.h>
#include<unistd.h>
#include <fcntl.h>
#include<errno.h>
#define MYFIFO "myfifo"
#define BUFFSIZE 1024
int main()
{
int fd;
char buf[BUFFSIZE];
if(access(MYFIFO,F_OK) == -1)
{
if(mkfifo(MYFIFO,0666)== -1)
{
printf("%s",strerror(errno));
return -1;
}
}
fd = open(MYFIFO,O_WRONLY);// 已只写方式打开管道文件
if(fd == -1)
{
printf("%s",strerror(errno));
return -1;
}
memset(buf,0,BUFFSIZE);
strcpy(buf,"hello fifo \n");
if(write(fd,buf,strlen(buf))>0)//写管道
{
printf("write %s success",MYFIFO);
}
else
{
printf("%s",strerror(errno));
}
close(fd);
return 0;
}