进程间通信-管道与管道容量

匿名管道是一种最基本的IPC机制,由pipe函数创建:
#include <unistd.h>
int pipe(int filedes[2]);

参数:输出型参数,调用pipe函数时在内核中开辟一块缓冲区(称为管道文件)用于通信,它有一个读端一个写端,然后通过filedes参数传出两个文件描述符,filedes[0]=3指向管道的读端,filedes[1]=4指向管道的写端。

返回值:pipe函数调用成功返回0,调用失败返回-1。


匿名管道在通信中有以下特点:

1.两个进程只能实现单向通信;

2.只有血缘关系的进程才可以通信;(此特点是其与命名管道唯一的区别)

3.管道的生命周期随进程的结束而结束;

4.管道通信的传输为面向字节流;

5.匿名管道自带同步机制。


实现机制如下:




在此处代码实现中第三步骤则改为父进程关闭fd[1]负责读,子进程关闭fd[0]负责写:

#include <stdio.h>
#include <unistd.h>
int main()
{
	int fd[2];
	if(pipe(fd)<0)  //打开匿名管道 
	{
		perror("pipe");
		return -1;
	}
	else  //成功 
	{
		int id=fork();   //创建子进程 
		if(id==0) //child write
		{
			close(fd[0]);   //关闭管道文件读端 
			char buf[1024];
			while(1)
			{
				//从标准输入(键盘)输入消息 
				printf("Please Enter#");
				fflush(stdout);
				//读到buf中 
				ssize_t s=read(0,buf,sizeof(buf));
				if(s>0)
				{
					buf[s-1]=0;
				}
				
				//从buf中写入管道文件中 
				sleep(1);
				write(fd[1],buf,sizeof(buf));
				sleep(1);
			}
		}
		else   //father  read
		{
			close(fd[1]);   //关闭管道文件写端 
			char buf[1024];
			while(1)
			{
				buf[0]=0;
				ssize_t s=read(fd[0],buf,sizeof(buf));   //父进程从管道文件中读取消息 
				if(s>0)
				{
					buf[s-1]=0;
					printf("%s\n",buf);
				}
			}
		}
	}
	return 0;
}
效果如下:


在管道实现中会出现以下四种情况(以代码实现为例):

1.父进程若不读且并不关闭fd[0],则子进程写满管道后会自行阻塞等待直至父进程来读取(由此可测出管道容量,如下一个代码就以此为原理实现);

2.子进程若不写且并不关闭fd[1],则父进程不读会阻塞等待直至子进程来写;

3.父进程若不读并关闭了fd[0],则操作系统会关闭在写的子进程;

4.子进程若不写并关闭了fd[1],则父进程相当于读一个文件,当文件读完则退出,返回0值。


以下则以上面第一种情况为例测出管道的容量:

#include <stdio.h>
#include <unistd.h>
void CapacityOfPipe()
{
	int fd[2];
	pipe(fd);   //打开管道文件 
	
	//定义初始化buf大小为4K 
    char buf[4096];
	int i=0;
	for(;i<sizeof(buf);++i)
    {
	    buf[i]='1';
    }
	
	i=0;
    for(;i<100;++i)
    {  
    	//每次向管道文件写入4K大小,最后若阻塞则最后一次大小为管道总容量 
		ssize_t s=write(fd[1],buf,sizeof(buf));
		if(s<0)
		{
			perror("write");
		}
		else		
		{
			printf("%d ",s);
			printf("Capacity## %d*4K=%dk\n",i,i*4);
		}
    }
    
    //关闭管道文件 
	close(fd[0]);
	close(fd[1]);
}
int main()
{
	CapacityOfPipe();
	return 0;
}
结果如下:


可知在第15次以后管道已满开始阻塞等待,此时的容量大小为60kb,即可得出我的linux系统下管道容量为64kb.


命名管道(FIFO)的实现:

其与匿名管道区别:与血缘关系无关,可以让相互无关的进程进行通信。

代码实现:实质为读写一份共同管道文件。

server.c:(读)

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

int main()
{
	umask(0);
	if(mkfifo("PipeFile",S_IFIFO|0666)<0)
	{
		perror("mkfifo");
		return -1;
	}
	else
	{ 
		int fd=open("PipeFile",O_RDONLY);
		char buf[1024];
		while(1)
		{
			buf[0]=0;
			ssize_t s=read(fd,buf,sizeof(buf));
			if(s<=0)
			{
				perror("read");
				return -2;
			}
			else
			{
				buf[s-1]=0;
				printf("%s\n",buf);
			}

		}
		close(fd);		
	}

	return 0;
}


client.c(写)

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
int main()
{
	int fd=open("PipeFile",O_WRONLY);
	char buf[1024];
	while(1)
	{
		printf("Please Enter#");
		fflush(stdout);

		ssize_t s=read(0,buf,sizeof(buf));
		if(s<0)
		{
			perror("read");
			return -1;
		}
		else
		{
			buf[s-1]=0;
			write(fd,buf,sizeof(buf));
		}
	}
	close(fd);
	return 0;
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章