进程间通讯(2)---管道

管道:半双工通讯

数据流向是单向的、先进先出的。只能一个进程读、一个进程写。数据从管道中读出后,就会被删除。如果管道中没有数据,读操作就会被阻塞,直到管道中有数据可读;而如果管道的满的,写操作就会被阻塞,直到管道中有足够大的空间可用。

 

有名管道(fifo):在任意两个进程间通信。有属性信息、inode结点存在磁盘上。

在文件目录树中存在管道文件标识。但是管道文件不占据磁盘空间,需要传递的数据缓存在内存区域。

通过mknode() 系统调用或mkfifo()函数来建立。因为Linux系统为每一个文件都提供了访问权限,所以只要两个进程都有操作FIFO的权限,就能通过文件名将其打开、进行读写。FIFO在内存中释放,但磁盘结点仍然存在。可以通过unlink函数删除管道。

无名管道(pipe):用于父子进程之间。无属性信息,没有inode结点。通过pipe()系统调用创建并打开,当最后使用它的进程关闭对它的引用时,pipe自动撤销。

 

通信过程:(依然是文件操作那一套):管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在于内存中。

管道的实质是内核缓冲区,有名管道和无名管道都是通过内核缓冲区实现数据传输。

 

     

 

创建有名管道文件  & 有名管道的使用:

(命令)mkfifo 文件名

(函数)int mkfifo(const char *pathname, mode_t mode)

第一个参数将要在文件系统中创建一个专用文件,第二个参数来规定FIFO的读写权限,不能用open创建一个管道文件。

/*
 *写端
*/
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>

#define FIFO "myfifo"

int main()
{
	int fd;
	char buff[128] = {0};
	int n;

	//打开管道
	fd = open(FIFO,O_WRONLY);

	fgets(buff,127,stdin);
	buff[strlen(buff) -1] == 0;

	//向管道中写入数据
	n = write(fd,buff,strlen(buff));

	close(fd);

}

	
/*
 *读端
*/
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>


#define FIFO "myfifo"

int main()
{
	int fd;
	char buff[128] = {0};
	int n;

	//创建管道
	if((mkfifo(FIFO, 0664)<0) && errno != EEXIST)
	{
		printf("创建管道失败");
	}
	//打开管道
	fd = open(FIFO,O_RDONLY);
	if(fd == -1)
	{
		perror("open");
		exit(1);
	}
	//读取数据
	n = read(fd,buff,127);	
	printf("从管道中读出的数据:%s\n",buff);

	close(fd);
	unlink(FIFO);
}

有名管道文件的操作:

              创建:int mkfifo(const char *pathname, mode_t mode)

              打开:int open(char *path,int flag)

              读:int read( int fd, void *buff, size_t size)

              写:int write( int fd, void *buff, size_t size)

              关闭:int close( int fd )

              删除:int unlink(const char *pathname)

 

       一旦创建了一个FIFO,就可用open打开它,但使用mkfifo函数创建管道时,注意在哪个进程源文件中创建管道,就要先运行哪个进程,否则,另一个进程会因为管道不存在而无法打开管道。

 

创建无名管道 & 无名管道的使用:

  int pipe(int filedis[2]);   0端用于读管道,1端用于写管道

#include<stdio.h>
#include<unsiatd.h>
#include<string.h>

int main()
{
	pid_t fd;
	char buff[1024] = {0};
	int pipe_fd[2]; //有名管道的文件描述符
	
	if(pipe(pipe_fd) < 0)   //创建有名管道
	{
		printf("创建管道失败");
		return 0;
	}
	
	fd = fork();  //fork一个子进程
	if(fd == 0)   //在子进程中
	{
		close(pipe_fd[1]);   //关闭管道的写端
		if( (n = read(pipe_fd[0],buff,1024))  > 0 )
		{
			printf("子进程从管道中读取的数据:%s\n",buff);  
		}
		close(pipe_fd[0]);
		exit(0);
	}
	else if(fd > 0 )  //在父进程中
	{
		close(pipe_fd[0]);
		write(pipe_fd[1],"hello my son!",13);  //相关到中写入数据
		close(pipe_fd[1]);
		
		sleep(2);
		wait(fd);  //调用wait等待子进程结束
		exit(0);
	}
}

   无名管道的操作:

              创建管道:int pipe(int pipefd[2])

              读:int read( int fd, void *buff, size_t size)

              写:int write( int fd, void *buff, size_t size)

              关闭:int close( int fd )

猜你喜欢

转载自blog.csdn.net/Dxiaoru/article/details/81272743