管道創建主要是兩種:無名管道和有名管道(命名管道)
無名管道(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 管道名 來創建有名管道。方法和上面的一樣,只是省去了創建管道文件那個操作。