有名管道和无名管道

管道:

1. 管道是Unix系统最古老的进程间通信方式,其实质是一个虚拟文件,是在内核中维护了一个消息队列。

2. 历史上的管道通常是指半双工管道,只允许数据单向流动。现代系统大都提供全双工管道,数据可以沿着管道双向流动。


有名管道(fifo):

1.  概念:基于有名文件(管道文件)的管道通信

2. 命令形式:

    # mkfifo fifo  创建管道

    # echo hello > fifo   读入hello到管道中

    # cat fifo   查看管道中内容

   演示:

   

   

注意:

        1. 执行echo 命令式 第一个终端是阻塞在write上的,只有用第二个终端cat后,才解除阻塞

         2.管道自身是不占内存的,可以用ls  -l 命令查看 :第一个p表示piple

        

3.  编程模型: 

       

4.  编程实现:写进程:wfifo.cpp

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>

#define FIFO_FILE "/tmp/fifo"

int main (void) {
	printf ("创建管道...\n");
	if (mkfifo (FIFO_FILE, 0666) == -1) {
		perror ("mkfifo");
		return -1;
	}
	printf ("打开管道...\n");
	int fd = open (FIFO_FILE, O_WRONLY);
	if (fd == -1) {
		perror ("open");
		return -1;
	}

	printf ("发送数据...\n");
	for (;;) {
		printf ("> ");
		char buf[1024];
		gets (buf);
		if (! strcmp (buf, "!"))
			break;

		if (write (fd, buf, (strlen (buf) + 1) *
			sizeof (buf[0])) == -1) {
			perror ("write");
			return -1;
		}
	}
	printf ("关闭管道...\n");
	if (close (fd) == -1) {
		perror ("close");
		return -1;
	}

	printf ("删除管道...\n");
<span style="white-space:pre">	</span>if (unlink (FIFO_FILE) == -1) {
		perror ("unlink");
		return -1;
	}
	printf ("大功告成!\n");
	return 0;
}
读进程:rfifo.cpp

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

#define FIFO_FILE "/tmp/fifo"

int main (void) {
	printf ("打开管道...\n");
	int fd = open (FIFO_FILE, O_RDONLY);
	if (fd == -1) {
		perror ("open");
		return -1;
	}
	printf ("接收数据...\n");
	for (;;) {
		char buf[1024];
		ssize_t rb = read (fd, buf, sizeof (buf));
		if (rb == -1) {
			perror ("read");
			return -1;
		}

		if (! rb)//rb=0说明管道的另外一段被关闭了
			break;

		printf ("< %s\n", buf);
	}

	printf ("关闭管道...\n");
	if (close (fd) == -1) {
		perror ("close");
		return -1;
	}
	printf ("大功告成!\n");
	return 0;
}
运行两个进程:

    

  

注意:

① 当管道是通的时候,open函数才会执行。

②  当管道两端都关闭的时管道才会被卸载

③当读到的是!时候,写端被关闭,此时read读到的是0,读端也被关闭,否则读端阻塞在read函数,写端阻塞在write函数


思考:当我们开三个终端,一个写两个读,会是导致什么结果?

     当一个管道被多个进程去读的时候,不定谁读到,得看cpu的切换,看cpu给谁时间(开三个终端,一个写,俩个读),此时我们应该使用多客户机模型。

  

        从图中可以看出:请求从共有管道发出,应答从私有管道发出,共有管道由服务器建立,私有管道由各自的客户端建立,保证数据发送不会混乱。


无名管道(pipe)

头文件:#include <unistd.h>

int pipe (int pipefd[2]);
  1) 成功返回0,失败返回-1。
  2) 通过输出参数pipefd返回两个文件描述符,其中pipefd[0]用于读,pipefd[1]用于写。

特别使用与父子进程之间的通信

      

使用方法:
     A. 调用该函数在内核中创建管道文件(看不到,是个虚拟文件,是内核在虚拟内存中创建的),并通过其输出参数, 获得分别用于读和写的两个文件描述符;
     B. 调用fork函数,创建子进程;
     C. 写数据的进程关闭读端(pipefd[0]),读数据的进程关闭写端(pipefd[1]);
     D. 传输数据;
     E. 父子进程分别关闭自己的文件描述符。

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

int main (void) {
	printf ("父进程:创建管道...\n");
	int pipefd[2];
	if (pipe (pipefd) == -1) {
		perror ("pipe");
		return -1;
	}
	printf ("父进程:创建进程...\n");
	pid_t pid = fork ();
	if (pid == -1) {
		perror ("fork");
		return -1;
	}

	if (pid == 0) {
		printf ("子进程:关闭写端...\n");
		close (pipefd[1]);
		printf ("子进程:接收数据...\n");

		for (;;) {
			char buf[1024];
			ssize_t rb = read (pipefd[0], buf, sizeof (buf));
			if (rb == -1) {
				perror ("read");
				return -1;
			}

			if (! rb)
				break;

			puts (buf);
		}

		printf ("子进程:关闭读端...\n");
		close (pipefd[0]);
		printf ("子进程:大功告成!\n");
		return 0;
	}

	printf ("父进程:关闭读端...\n");
	close (pipefd[0]);
	printf ("父进程:发送数据...\n");
	for (;;) {
		char buf[1024];
		gets (buf);
		if (! strcmp (buf, "!"))
			break;

		if (write (pipefd[1], buf, (strlen (buf) + 1) *
			sizeof (buf[0])) == -1) {
			perror ("write");
			return -1;
		}
	}

	printf ("父进程:关闭写端...\n");
	close (pipefd[1]);
	if (wait (0) == -1) {
		perror ("wait");
		return -1;
	}

	printf ("父进程:大功告成!\n");
	return 0;
}

 

这个程序中最重要的就是对fork函数的理解,可以参考:

http://blog.csdn.net/meetings/article/details/47123359


有名管道和无名管道的区别:

     无名管道是单工模式,命名管道是全双工模式
     有名管道是通过一个有名的文件在读写两端建立联系,而无名管道则是通过文件描述符来在父子进程间建立联系的。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值