Linux进程间通信——无名/有名管道

版权声明:Dream_dog专属 https://blog.csdn.net/Dog_dream/article/details/83750245

管道简介:

管道是Linux中进程间通信的一种方式,它把一个进程的输出直接连接另一个管道的输入。Linux的管道包括两种:无名管道和有名管道。

1.无名管道

特点:

  1. 只能用于具有亲缘关系的进程间通信(及父子或者兄弟进程)。
  2. 是一种单工的通信模式,具有固定的读端和写端。
  3. 管道也可以看成一种特殊的文件进行操作,对于它的读写也可以使用普通的read(),write()等函数。但是它不属于任何文件系统,并且只存在于内核中。
  4. 数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。

注意:

  1. 只有在管道的读端存在时,向管道写入数据才有意义,否则,向管道写数据的进程将收到内核传来的SIGPIPE信号(通常Broken Pipe错误)。
  2. 向管道写入数据时,Linux将不具有原子性,管道缓冲区只要有空间,写进程就试图向管道写数据。如果管道缓冲区已满,那么写操作将会一直阻塞。
  3. 父进程在运行时,它们的先后次序并不能保证。为了确保父进程已经关闭了相应的文件描述符,可在两个进程中调用sleep()函数。

管道创建函数:

所需头文件: #include<unistd.h>

函数原型: int pipe(int fd[]);

参数:fd:大小为2的整形数组,用于存放管道的文件描述符。

返回值:成功:0         错误:-1;

实例:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/wait.h>

int main(int arg,char *argv[])
{
	int fdpi[2]={0};//无名管道的套接的描符存放地址
	char buf[1024];
	if(pipe(fdpi)==-1)
	{
		perror("create pipe is error\n");
		return 0;
	}
	pid_t pid=fork();
	if(pid==-1)
	{
		perror("create fork is error\n");
		return 0;
	}
	else if(pid==0)
	{
		while(1)
		{
        	close(fdpi[0]);//关闭读端口
			bzero(buf,sizeof(buf));//清空缓存区
			gets(buf);
			 if(write(fdpi[1],buf,sizeof(buf))==-1)
			{
				perror("write in fdpi[1] is error\n");
				exit(0);
			}
			if(strcmp("EOF",buf)==0)
			{
				break;
			}
		}
		printf("chid:%d  is quit\n",getpid());	
	}
	else 
	{
		while(1)
		{
		    close(fdpi[1]);//关闭写端口
			bzero(buf,sizeof(buf));
			if(read(fdpi[0],buf,sizeof(buf))<0)
			{
				perror("read is error\n");
				exit(0);
			}
			if(strcmp("EOF",buf)==0)
			{
				break;
			}
			else
			{
			printf("child message is %s\n",buf);
			}
		}
	    close(fdpi[0]);
	    close(fdpi[1]);
		int cpid=wait(NULL);
		printf("my child: %d is quit\n",cpid);
	}
	return 0;
}

2.有名管道

特点:

扫描二维码关注公众号,回复: 4342727 查看本文章
  1. 它可以使互不相关的两个进程实现彼此通信。
  2. 该管道可以通过路径名来指出,并且在文件系统中是可以见的。在建立管道之后,两个进程就可以把它当作普通文件进行读写操作,使用非常方便。
  3. FIFO严格地遵循先进先出规则,对管道及FIFO的读总是从开始处返回数据,对它们的写规则把数据添加到末尾。有名管道不支持如lseek()等文件定位操作。

注意:当一个进程有名管道创建成功后有一直阻塞在哪里等待另一个进程使用这个管道。

函数:

头文件:#include<sys/types.h>   #include<sys/state.h>

原型函数:int mkfifo(const char* filename,mode_t mode)

参数:filename:   管道名称             mode:管道的访问权限

返回值:成功   0    失败  -1

错误信息:

EACCESS     参数pathname所指定的目录路径无可执行的权限

EEXIST    参数pathname所指定的文件已存在。

ENAMETOOLONG   参数pathname的路径名称太长。

ENOENT    参数pathname包含的目录不存在

ENOSPC   文件系统的剩余空间不足

ENOTDIR   参数pathname路径中的目录存在但却非真正的目录。

EROFS    参数pathname指定的文件存在于只读文件系统内。

实例

Makefile:

SOURCE = $(wildcard *.c)
TARGETS = $(patsubst %.c, %, $(SOURCE))

CC = gcc
CFLAGS = -Wall -g

all:$(TARGETS)

$(TARGETS):%:%.c
		$(CC) $< $(CFLAGS) -o $@
.PHONY:clean all
clean:
	-rm -rf $(TARGETS)

head:

#ifndef   A_H

#define   A_H

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/stat.h>
#include<fcntl.h>

#define EXIT_FALLURE -1
#define MAX_MASG   1024
#define FIOF_C "fiof_c"
#define FIOF_S "fiof_s"

#endif

server:

#include"./head.h"
int main(int argc,char *argv[])
{
	char send_buf[1024];
	char recv_buf[1024];
	int  send_fd,recv_fd;//有名管道的描述符
	if(access(FIOF_S, F_OK) == -1)
	 {
			if((send_fd=mkfifo(FIOF_S,0666))==-1)//创建管道
			{
				perror("mkfifo is error\n");
	    		exit(EXIT_FALLURE);
			}
	 }
	if((send_fd=open(FIOF_S,O_WRONLY))==-1)//打开写管道
	{
		perror("open FIOF_S is error\n");
		exit(EXIT_FALLURE);
	}
	if((recv_fd=open(FIOF_C,O_RDONLY))==-1)//打开读管道
	{
		perror("open FIOF_C is error\n");
		exit(EXIT_FALLURE);
	}
	puts("#######################");
	while(1)
	{
		printf("serv ->:");
		bzero(send_buf,sizeof(send_buf));
		fgets(send_buf,sizeof(send_buf),stdin);
		send_buf[strlen(send_buf)-1]=0;
		if(write(send_fd,send_buf,strlen(send_buf)+1)==-1)
		{
			perror("write is error");
			exit(EXIT_FALLURE);
		}
		if(strcmp(send_buf,"quit")==0)
		{
			break;
		}
		if(read(recv_fd,recv_buf,sizeof(recv_buf))==-1)
		{
			perror("read is error");
			exit(EXIT_FALLURE);
		}
		printf("client say is-->:%s\n",recv_buf);
		if(strcmp(recv_buf,"quit")==0)
		{
			break;
		}
	}
    close(send_fd);
	close(recv_fd);
	unlink(FIOF_S);
	return 0;
}

client:

#include"./head.h"
int main(int argc,char *argv[])
{
	char send_buf[1024];
	char recv_buf[1024];
	int  send_fd,recv_fd;//有名管道的描述符
	if(access(FIOF_C, F_OK) == -1)
	 {
			if((send_fd=mkfifo(FIOF_C,0666))==-1)//创建管道
			{
				perror("mkfifo is error\n");
	    		exit(EXIT_FALLURE);
			}
	 }
	puts("#######################");
	if((recv_fd=open(FIOF_S,O_RDONLY))==-1)//打开读管道
	{
		perror("open FIOF_S is error\n");
		exit(EXIT_FALLURE);
	}
	if((send_fd=open(FIOF_C,O_WRONLY))==-1)//打开写管道
	{
		perror("open FIOF_C is error\n");
		exit(EXIT_FALLURE);
	}
	while(1)
	{
		if(read(recv_fd,recv_buf,sizeof(recv_buf))==-1)
		{
			perror("read is error");
			exit(EXIT_FALLURE);
		}
		
		printf("serv say is-->:%s\n",recv_buf);
		if(strcmp(recv_buf,"quit")==0)
		{
			break;
		}
		printf("clinet ->:");
		bzero(send_buf,sizeof(send_buf));
		fgets(send_buf,sizeof(send_buf),stdin);
		send_buf[strlen(send_buf)-1]=0;
		if(write(send_fd,send_buf,strlen(send_buf)+1)==-1)
		{
			perror("write is error");
			exit(EXIT_FALLURE);
		}
		if(strcmp(send_buf,"quit")==0)
		{
			break;
		}
	}
    close(send_fd);
	close(recv_fd);
	unlink(FIOF_C);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Dog_dream/article/details/83750245
今日推荐