进程间的通信:管道与FIFO


前言

管道:无名管道,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;  
}

在这里插入图片描述


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值