進程間通信之管道

一 管道通信:

1,管道:管道是單向的、先進先出的,它把一個進程的輸出和另一個進程的輸入連接在一起。一個進程的尾部寫入數據,另一個進程的頭部讀出數據。

2,進程間數據的傳遞:popen和pclose

 #include <stdio.h>
       FILE *popen(const char *command, const char *type);
       int pclose(FILE *stream);

p
open函數允許一個程序將另一個程序作爲新進程來啓動,並可以傳遞數據給他或者通過他接收數據。command字符串是要運行的程序名和參數,type 必須是"r"或"w"

pclose函數只在popen啓動的進程結束後才返回。如果調用pclose時它仍在運行,pclose將等待該進程的結束。

#include <stdio.h>

#define SIZE 1024

int main()
{
	//FILE *popen(const char *command, const char *type);
	FILE *fp = popen ("ls","r");
	if(fp == NULL)
	{
		perror("popen fp");
		return -1;
	}
	
	char buf[SIZE] = {0};
	
	int ret = fread (buf,sizeof(char),SIZE-1,fp);
	//printf("%s\n",buf);
	
	FILE *fp2 = popen("ls -l","w");
	if(fp2 == NULL)
	{
		perror("popen fp2");
		return -1;
	}
	
	fwrite (buf,sizeof(char),ret,fp2);
	printf("%s\n",buf);
	
	pclose(fp);
	return 0;
}
輸出結果爲:

[root@promote 7-進程通信]# ./a.out 
總計 9
-rwxrwxrwx 1 root root  472 2017-08-13 1-管道.c
-rwxrwxrwx 1 root root 5550 2017-08-13 a.out
1-管道.c
a.out
二 管道類型:無名管道和有名管道

1,無名管道:用於父子進程之間的通信

無名管道由pipe()創建:#include <unistd.h>      int pipe(int filedes[2]);

創建一個無名管道:

當一個管道建立時,會創建兩個文件描述符:fd[0]用於讀管道,fd[1]用於寫管道。


int main()
{
	//int pipe(int filedes[2]);
	int fd[2];
	int ret = pipe(fd);
	if(ret == -1)
	{
		perror("pipe ");
		return -1;
	}
	else
	{
		printf("create success\n");
	}
	
	close(fd[0]);
	close(fd[1]);
	
	return 0;
}
2,無名管道的讀寫:

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

#define SIZE 1024

void children(int *fd)
{
	close(fd[1]);//子進程關閉寫端
	
	char buf[SIZE];
	
	while(1)
	{
		int ret = read(fd[0],buf,SIZE-1);
		if(ret == -1)
		{
			perror("read ");
			return;
		}
		buf[ret] = '\0';//字符串末尾設置'\0'
		printf("讀到%d字節: %s",ret,buf);
	}
	
	close(fd[0]);//關閉讀端
	
	return;
}

void father(int *fd)
{
	close(fd[0]); //父進程關閉讀端
	
	char buf[SIZE];
	while(1)
	{
		fgets(buf,SIZE,stdin);
		int ret = write (fd[1],buf,strlen(buf));//父進程發送數據
		printf("父進程發送%d 字節\n",ret);
	}
	
	close(fd[1]);//關閉寫端
	
	return;
}

int main()
{
	int fd[2];  //創建一個無名管道
	int ret = pipe(fd);
	if(ret == -1)
	{
		perror("pipe ");
		return -1;
	}
	
	pid_t pid = fork(); //創建一個子進程
	if(pid == -1)
	{
		perror("fork ");
		return -1;
	}
	if(pid == 0)
	{
		children(fd);
	}
	else
	{
		father(fd);
	}
	
	return 0;
}
父進程一邊寫入,子進程一邊讀出:

[root@promote 7-進程通信]# ./a.out 
qwe
父進程發送4 字節
讀到4字節: qwe
qwe
父進程發送4 字節
讀到4字節: qwe
qwe
父進程發送4 字節
讀到4字節: qwe
3,用管道實現文件複製:

之前系統調用中講到可以用read,write複製文件,現在也可以用管道來實現:

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

#define SIZE 2048

int children(int *fd)
{
	close(fd[1]);
	
	int fd2 = open("4.mmap",O_WRONLY | O_CREAT,0777);
	if(fd2 == -1)
	{
		perror("open fd2 ");
		return -1;
	}
	
	char buf[SIZE] = {0};
	int ret;
	while(ret = read(fd[0],buf,SIZE))
	{
		if(ret == -1)
		{
			perror("read ");
			return -1;
		}
		write(fd2,buf,ret);
	}
	
	printf("read over \n");
	
	close(fd[0]);
	close(fd2);
	
	return 0;
}

int father(int *fd)
{
	close(fd[0]);
	
	int fd1 = open("3.mmap",O_RDONLY);
	if(fd1 == -1)
	{
		perror("open fd1 ");
		return -1;
	}
	
	char buf[SIZE] = {0};
	int ret;
	while(ret = read(fd1,buf,SIZE))
	{
		if(ret == -1)
		{
			perror("read ");
			return -1;
		}
		write(fd[1],buf,ret);
	}
	
	close(fd[1]);
	close(fd1);
	
	return 0;
}
int main()
{
	int fd[2];  //創建一個無名管道
	int ret = pipe(fd);
	if(ret == -1)
	{
		perror("pipe ");
		return -1;
	}
	
	pid_t pid = fork(); //創建一個子進程
	if(pid == -1)
	{
		perror("fork ");
		return -1;
	}
	if(pid == 0)
	{
		children(fd);
	}
	else
	{
		father(fd);
	}
	
	return 0;
}

文件成功複製:

4,有名管道FIFO:

#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);

創建一個命名管道:

#include <sys/types.h>
#include <sys/stat.h>

int main()
{
	//int mkfifo(const char *pathname, mode_t mode);
	int ret = mkfifo("/home/fifo",0777);
	if(ret == -1)
	{
		perror("mkfifo ");
		return -1;
	}
	return 0;
}







  


發佈了58 篇原創文章 · 獲贊 12 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章