前言
管道:无名管道,pipe()单向传递,父子进程之间进行传递 read write
FIFO:有名管道,mkfifo(),任意进程。open read write close unlink
一、管道pipe()
字节流传输,一次传输按规定大小才传送出去。
注意关闭未使用管道文件描述符
函数说明
pipe(建立管道):
1) 头文件 #include<unistd.h>
2) 定义函数: int pipe(int filedes[2]);
3) 函数说明: pipe()会建立管道,并将文件描述词由参数filedes数组返回。
filedes[0]为管道里的读取端
filedes[1]则为管道的写入端。
4) 返回值: 若成功则返回零,否则返回-1,错误原因存于errno中。
错误代码:
EMFILE 进程已用完文件描述词最大量
ENFILE 系统已无文件描述词可用。
EFAULT 参数 filedes 数组地址不合法。
若需要设置为非阻塞,则可做如下设置:
fcntl(filedes[0], F_SETFL, O_NONBLOCK);
fcntl(filedes[1], F_SETFL, O_NONBLOCK);
int read(int fd,char * buf,int size);
read默认是阻塞读,返回read实际读到的个数,当全部写入端被close后,
read会返回0退出阻塞
int write(int fd,char * buf,int size);
需要达到参数size的大小才可以写入成功。若buf实际个数大于size,会被切成一块一块,
那么可能就会阻塞。
当 写入端被close 读取端read()会一直阻塞以等待数据
当 读取端被close 写入端wirte()会因EPIPE错误而失败
demo.c
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
int main()
{
int pipefd[2];
int ret;
pid_t pid;
char buf[20];
ret = pipe(pipefd);
if(ret)
{
printf("error pipe\r\n");
}
pid = fork();
if(pid < 0)
{
printf("fork error\r\n");
}
else if(pid == 0)
{
close(pipefd[0]);
while(1)
{
printf("input massage(end quit ):\r\n");
scanf("%s",buf);
ret = write(pipefd[1],buf,strlen(buf)+1);
if(strcmp(buf,"end")== 0)
{
_exit(0);
}
sleep(1);
}
}
else
{
close(pipefd[1]);
while(1)
{
ret = read(pipefd[0],buf,sizeof(buf));
if(ret > 0)
{
printf("read : %s \r\n",buf);
}
if(ret == 0 || strcmp(buf,"end")== 0)
break;
}
wait(NULL);
}
close(pipefd[1]);
close(pipefd[0]);
return 0;
}
二、FIFO
与管道类似、差别在于FIFO文件系统中拥有一个名称,这样就能够将FIFO用于非相关进程之间的通讯。
一旦打开FIFO,就可以用 read、write、close
1.FIFO创建mkfifo()
函数原型: int mkfifo(const char* pathname, mode_t mode);
函数描述:创建一个FIFO文件
参数:
Pathname:指出想要创建的FIFO路径,
Mode:指定创建的FIFO访问模式。
返回:0 成功 -1时表示创建过程中遇到某种错误,此时会设置errno,用户可以检测errno来取得进一步
信息:
EACCES: 路径所在的目录不允许执行权限
EEXIST:路径已经存在,这时包括路径是一个符号链接,无论它是悬空还没有悬空。
ENAMETOOLONG:要么全部的文件名大于PATH_MAX,要么是单独的文件名大于NAME_MAX。
在GNU系统里没有这个文件名长度的限制,但在其它系统里可能存在。
ENOENT:目录部分不存在,或者是一个悬空链接。
ENOTDIR:目录部分不一个目录。
EROFS:路径指向一个只读的文件系统。
2、open()、read()、write()
int open(const char *pathname, int flags);
函数说明:打开FIFO文件
参数:
Pathname;FIFO文件路径
Flags:打开模式,注意事项两点如下所示。
打开FIFO文件和普通文件的区别有2点:
1、是不能以O_RDWR模式打开FIFO文件进行读写操作。这样做的行为是未定义的。
因为我们通常使用FIFO只是为了单向传递数据,所以没有必要使用这个模式。
如果确实需要在程序之间双向传递数据,最好使用一对FIFO或管道,一个方向使用一个。
或者采用先关闭在重新打开FIFO的方法来明确改变数据流的方向。
2、对标志位的O_NONBLOCK选项的用法
使用这个选项不仅改变open调用的处理方式,还会改变对这次open调用返回的文件描述符进行的
读写请求的处理方式。
O_RDONLY、O_WRONLY和O_NONBLOCK标志共有四种合法的组合方式:
flags=O_RDONLY:open将会调用阻塞,除非有另外一个进程以写的方式打开同一个FIFO,
否则一直等待。
flags=O_WRONLY:open将会调用阻塞,除非有另外一个进程以读的方式打开同一个FIFO,
否则一直等待。
flags=O_RDONLY|O_NONBLOCK:如果此时没有其他进程以写的方式打开FIFO,此时open也会
成功返回,此时FIFO被读打开,而不会返回错误。
flags=O_WRONLY|O_NONBLOCK:立即返回,如果此时没有其他进程以读的方式打开,open会失
败打开,此时FIFO没有被打开,返回-1。
open的相互制约:
read的读取状况:
write的写入状况:
3、FIFO删除unlink()
int unlink(const char *pathname);
功能:FIFO文件使用完毕之后需删除,以免造成垃圾文件。
参数:
Pathname:FIFO文件路径
write.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define FIFO_NAME "./myfifo"
#define BUF_SIZE 128
int main( void )
{
int fd;
char buf[BUF_SIZE]="hello procread,i come frome process named procwrite";
if(access(FIFO_NAME, F_OK) == -1)
{
if(mkfifo(FIFO_NAME,S_IFIFO|0666)==-1)
{
perror("mkfifo error!");
exit(0);
}
}
printf("mkfifo succes\r\n");
if((fd=open(FIFO_NAME,O_WRONLY))==-1){
perror("open fifo error!");
exit(0);
}
printf("open succes\r\n");
while(1){
printf("input message to be sent(end to quit):");
scanf ("%s",buf);
write(fd,buf,strlen(buf)+1);
if(strcmp(buf, "end")==0)
break;
}
close(fd);
unlink(FIFO_NAME);
return 0;
}
read.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include<fcntl.h>
#include <unistd.h>
#define FIFO_NAME "myfifo"
#define BUF_SIZE 128
int main( void )
{
int fd;
int ret;
char buf[BUF_SIZE];
if(access(FIFO_NAME, F_OK) == -1)
{
if(mkfifo(FIFO_NAME,S_IFIFO|0666)==-1)
{
perror("mkfifo error!");
exit(0);
}
}
fd=open(FIFO_NAME,O_RDONLY);
if(fd < 0)
{
perror("open fifo error!");
exit(0);
}
printf("open succes\r\n");
while(1)
{
memset(buf, 0, sizeof(buf));
ret = read(fd,buf,BUF_SIZE);
printf("read content:%s,%d\n",buf,ret);
if(strcmp(buf, "end")==0 || ret == 0)
break;
}
close(fd);
return 0;
}