進程間通信-管道與管道容量

匿名管道是一種最基本的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;
}




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