Linux基礎——管道

管道創建主要是兩種:無名管道和有名管道(命名管道)

無名管道(pipe函數)

  • 需要的頭文件:#include <unistd.h>

  • 函數: int pipe(int pipefd[2]);

  • 主要創建無名管道的方式:

int pipefd[2];	//名字隨意
if(pide(pipefd)<0)
{
	//創建失敗就報錯
	perror("pipe");
	exit(1);
}
  • 返回值:成功爲0,失敗爲-1
  • 無名管道的受限範圍:無名管道是用於血緣進程(父子進程)之間的通信,如果兩個進程不是血緣進程,那麼無法進行通信
  • 無名管道原理:這種管道建立之後,他們會在進程中佔用兩個文件符的位置,一個專門來讀,一個專門來寫,如下的左圖。具有方向性要麼是父寫子讀,關閉父讀子寫,要麼就是子寫父讀,關閉父寫子讀,他們之間是通過計算機的內核來實現的。看下圖中,紅黑箭頭只能存在一種(箭頭方向代表信息傳遞方向)。

無名管demo:

#include<sys/types.h>
#include<sys/stat.h> 
#include<unistd.h>
#include<fcntl.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
	int fd[2];
	pid_t pid;
	//創建管道
	if(pipe(fd) < 0)
	{
		//如果返回的是-1就代表創建失敗,0代表成功
		perror("pipe");
		exit(1);
	}
	
	//創建父子進程
	pid = fork();
	char str[1024] = "hello linux\n";
	char buf[1024];
	//父進程
	if(pid > 0)
	{
		close(fd[0]);	//父進程關閉讀
		write(fd[1],str,strlen(str));
	}
	else if(pid == 0)	//子進程
	{
		int len;
		close(fd[1]);	//子進程關閉寫
		len = read(fd[0],buf,sizeof(buf));	
		write(STDOUT_FILENO,buf,len);		//以標準形式輸出
	}
	else
	{
		perror("fork");	//進程異常處理
		exit(1);
	}
	while(1);
	return 0;
}

有名管道

有名管道用的是mkfifo,這個mkfifo有指令,也有函數。有名管道的原理和無名管道類似,都是通過一箇中轉的地方來通信,但是有名管道不是通過內核,而是通過磁盤創建一個節點來進行信號的中轉,該節點不佔空間。

有名管道特性

  • 當只寫打開FIFO管道時,如果沒有FIFO沒有讀端打開,則open寫打開會阻塞。
  • FIFO內核實現時可以支持雙向通信。(pipe單向通信,因爲父子進程共享同一個file 結構體)
  • FIFO可以一個讀端,多個寫端;也可以一個寫端,多個讀端

方法一:使用mkfifo函數

  • 需要的頭文件:#include <sys/types.h> 和 #include <sys/stat.h>
  • 函數:int mkfifo(const char *pathname, mode_t mode)
  • 參數解析:第一個參數爲創建出來的的管道文件名稱,第二個參數是該文件的權限
  • 返回值:-1失敗,0爲成功
  • 示例demo(這裏我分三個文件來寫)

創建有名管道的文件,該文件要先執行來創建一個管道

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

int main(void)
{
	int ret;
	//先刪除一下文件,防止重複創建
	unlink("FileTP");
	
	//創建命名管道,權限爲 rwx rwx rwx的文件(0表示無特殊權限s)
	ret = mkfifo("FileTP",0777);
	if(ret==0)
	{
	 printf("創建命名管道成功\n");
	}
	else //返回值爲-1
	{
	 printf("創建失敗\n");
	}
	
	return 0;
}

讀數據端的文件

#include<sys/types.h>
#include<sys/stat.h> 
#include<unistd.h>
#include<fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
	int fd,len;
	char buf[1024];
	
	//打開命名管道
	fd = open("FileTP",O_RDONLY);
	if(fd == -1)
	{
		//輸出報錯,關閉程序
		 perror("文件打開失敗\n");
	 	exit(1);
	}
	
	len = read(fd,buf,sizeof(buf));
	
	//write(STDOUT_FILENO,buf,len);
	printf("%s\n",buf);
		
	close(fd);
	return 0;
	}

寫數據端的文件

#include<sys/types.h>
#include<sys/stat.h> 
#include<unistd.h>
#include<fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
	int fd;
	char buf[] = "hello linux\n";
	
	printf("開始運行\n");
	fd = open("FileTP",O_WRONLY);
	if(fd == -1)
	{
		//輸出報錯,關閉程序
		perror("文件打開失敗\n");
		exit(1);
 
	}
	else
	{
		printf("成功打開了文件\n");
	}

	//寫文件
	write(fd,buf,sizeof(buf));
	printf("寫完了\n");
	
	close(fd);	
	return 0;
}

注意:執行的時候,當只寫打開FifeTP管道時,如果沒有FifeTP沒有讀端打開,則open寫打開會阻塞。即,你執行寫文件的時候,程序是不走的,只有你打開另外一個終端執行讀文件時,寫文件的程序纔會執行(用兩個終端執行兩個文件)

方法二:使用mkfifo指令

在終端輸入mkfifo 管道名 來創建有名管道。方法和上面的一樣,只是省去了創建管道文件那個操作。

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