無名管道和有名管道的概念與實現
1.管道是半雙工的,資料只能向一個方向流動;需要雙方通訊時,需要建立起兩個管道;
2.只能用於父子程式或者兄弟程式之間(具有親緣關係的程式);
3.單獨構成一種獨立的檔案系統:管道對於管道兩端的程式而言,就是一個檔案,但它不是普通的檔案,它不屬於某種檔案系統,而是自立門戶,單獨構成一種檔案系統,並且只存在與記憶體中。
4.資料的讀出和寫入:一個程式向管道中寫的內容被管道另一端的程式讀出。寫入的內容每次都新增在管道緩衝區的末尾,並且每次都是從緩衝區的頭部讀出資料。
5.從管道中讀取資料:
如果管道的寫端不存在,則認為已經讀到了資料的末尾,讀函式返回的讀出位元組數為0;
當管道的寫端存在時,如果請求的位元組數目大於PIPE_BUF,則返回管道中現有的資料位元組數,如果請求的位元組數目不大於PIPE_BUF,則返回管道中現有資料位元組數(此時,管道中資料量小於請求的資料量);或者返回請求的位元組數(此時,管道中資料量不小於請求的資料量)。注:(PIPE_BUF在include/linux/limits.h中定義,不同的核心版本可能會有所不同。Posix.1要求PIPE_BUF至少為512位元組,red hat 7.2中為4096)。
6.向管道中寫入資料:
向管道中寫入資料時,linux將不保證寫入的原子性,管道緩衝區一有空閒區域,寫程式就會試圖向管道寫入資料。如果讀程式不讀走管道緩衝區中的資料,那麼寫操作將一直阻塞。
注:只有在管道的讀端存在時,向管道中寫入資料才有意義。否則,向管道中寫入資料的程式將收到核心傳來的SIFPIPE訊號,應用程式可以處理該訊號,也可以忽略(預設動作則是應用程式終止)。
7。管道的主要侷限性正體現在它的特點上:
只支援單向資料流;
這個實驗建立了一個管道,並且實現了讀寫的操作
/*
============================================================================
Name : pipe.c
Author :
Version :
Copyright : Your copyright notice
Description : Hello World in C, Ansi-style
============================================================================
*/
#include <stdio.h>
#include <stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
int main(void) {
int fd[2];
int ret;
char p[20];
char *buf="hello!,pipe";
ret=pipe(fd);//將陣列名傳進去
//p=buf;這個是錯的,buf是一個變數,p[20]是變數,但是p是常量,不能被修改
//buf=p;這個是對的
if(ret==-1)
{
perror("pipe error");
exit(0);
}
else
{
int writeno=write(fd[1],buf,strlen(buf));//接受一下返回值,表示讀了多少個數字
if(writeno==-1)
{
perror("write error");
exit(1);//這時最好不要用負數,因為會影響到sataus,對於負數他是用補碼儲存的負數
}
int readno=read(fd[0],p,20);
if(readno==-1)
{
perror("read error");
exit(1);
}
p[readno]='\0';
printf("read pipe:%s\n",p);
exit(0);
}
return EXIT_SUCCESS;
}
結果:read pipe:hello!,pipe只能用於具有親緣關係的程式之間;
沒有名字;
管道的緩衝區是有限的(管道制存在於記憶體中,在管道建立時,為緩衝區分配一個頁面大小);
管道所傳送的是無格式位元組流,這就要求管道的讀出方和寫入方必須事先約定好資料的格式,比如多少位元組算作一個訊息(或命令、或記錄)等等;
管道應用的一個重大限制是它沒有名字,因此,只能用於具有親緣關係的程式間通訊
建立管道的方式:
int fd[2]
pipe(fd);
這裡的pipe函式的返回值:當成功時返回0,失敗時返回1,fd[0]代表這讀端,fd[1]代表著寫端
8.無名管道要注意的幾個問題
(1):交換管道的讀寫端,也就是將fd[0]換成fd[1],執行程式是會出錯的,因為,讀端只有讀許可權,寫端只有寫許可權,一旦調換,許可權將不允許,從而出現錯誤
(2):關閉管道寫端,從讀端讀資料.read函式返回值為0,表示讀管道檔案尾。
(3):關閉管道讀端,從寫端寫資料。 write error: Broken pipe。
此時出現管道破裂核心會向當前程式傳送SIGPIPE訊號,使用者程式對於此訊號的預設處理方式為終止當前進 程。
tcp程式設計中:當通訊的一端將套接字關閉,此時核心會向呼叫write函式的程式傳送SIGPIPE訊號,使用者程式對於此程式的預設處理方式為終止當前程式。
(4):不關閉寫端,從讀端讀資料: 此時read阻塞,直到寫端有資料寫入時,read 函式返回
fcntl函式可以設定讀管道時不阻塞。
(5):不關閉讀端,直接寫資料:是可以寫入的
(6):多次寫入一次讀取。如果讀取的buf夠大,會將管道中所有的資料讀出。
(7):一次寫入(10)多次讀取(10)。這個是好只能讀出一次,第二次讀的時候管道中無資料,read函式阻塞
通過利用同步互斥的原理實現程式間的通訊:
/*
============================================================================
Name : child2ConnecByLock.c
Author :
Version :
Copyright : Your copyright notice
Description : Hello World in C, Ansi-style
============================================================================
*/
#include <stdio.h>
#include <stdlib.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<string.h>
int main(void) {
int fd[2];
char buf1[20],buf2[20];
int ret=pipe(fd);
pid_t pid,pid2;
if(ret==-1)
{
perror("create pipe wrong!");
exit(0);
}
pid=fork();
if(pid==0)
{
lockf(fd[1],1,0);//鎖定對整個檔案的寫操作
strcpy(buf2,"child peocess1");
int writeno1=write(fd[1],buf2,20);
if(writeno1==-1)
{
perror("child1 1 wrong!");
exit(1);
}
sleep(1);
lockf(fd[1],0,0);//鎖定對整個檔案的寫操作
exit(1);
}
else if(pid>0)
{
pid2=fork();
if(pid2==0)
{
lockf(fd[1],1,0);
strcpy(buf2,"child process2");
int writeno2=write(fd[1],buf2,20);
if(writeno2==-1)
{
perror("child 2 wrong!");
exit(1);
}
sleep(3);
lockf(fd[1],0,0);
exit(1);
}
else if(pid2>0)
{
wait(NULL);
int readno1=read(fd[0],buf1,20);
printf("readno1 = %d",readno1);
buf1[readno1]='\0';
printf("%s\n",buf1);
wait(NULL);
int readno2=read(fd[0],buf2,20);
buf2[readno2]='\0';//
;本人這裡出現一個非常有意思的地方,當把這個操作刪除後,兩個程式依
//次輸出資訊,但是如果使用這個操作,雖然同樣出現了陣列的越界
printf("%s\n",buf2); exit(0); } } else { perror("carete child wrong!"); exit(1); } return EXIT_SUCCESS;}
有關popen和pclose
:
/*
============================================================================
Name : popen.c
Author :
Version :
Copyright : Your copyright notice
Description : Hello World in C, Ansi-style
============================================================================
*/
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *fp=NULL;
char buf[100];
if((fp=popen("ls -l","r"))==NULL)//
{
perror("popen wrong");
exit(1);
}
while(fgets(buf,100,fp)!=NULL)
{
printf("%s\n",buf);
}
if((fp=popen("cat >text","w"))==NULL)
{
perror("popen wrong");
exit(1);
}
fputs("helloworld!",fp);
pclose(fp);
//cat就是把標準輸入 輸出到標準輸出
//cat >txt,將標準輸入輸入到txt檔案裡面去
}
相關文章
- 有名管道程式碼
- Linux系統程式設計—有名管道Linux程式設計
- Linux程式間通訊②:有名管道FIFOLinux
- 介紹 Linux 中的管道和命名管道Linux
- JS 函式式概念: 管道 和 組合JS函式
- 匿名管道通訊實現
- 3|程式間通訊--有名管道學習筆記筆記
- 演算法鏈與管道(上):建立管道演算法
- ThinkPHP 6.0 管道模式與中介軟體的實現分析PHP模式
- 管道 |
- Linux中的管道是什麼?管道與共享記憶體的區別有哪些?Linux記憶體
- Flink基礎:實時處理管道與ETL
- angular 管道Angular
- 【linux】管道!!!Linux
- redis管道Redis
- Filter管道Filter
- Linux 管道Linux
- [Linux]管道Linux
- 自己動手實現 Shell 多程式管道符
- 利用windows api實現程式通訊(命名管道)WindowsAPI
- 老司機帶你實現 Laravel 之管道Laravel
- Linux的管道機制和重定向Linux
- 管道的學習
- [20190329]grep與管道檔案.txt
- 速度不夠,管道來湊——Redis管道技術Redis
- Redis效能提高之批量和管道Redis
- Golang —— goroutine(協程)和channel(管道)Golang
- Java的通過管道來實現執行緒通訊Java執行緒
- mongodb 聚合管道MongoDB
- windows命名管道Windows
- 管道系統
- Linux管道符Linux
- Linux 之管道Linux
- xargs 命令詳解,xargs 與管道的區別
- 使用管道流實現Java 8階段構建器Java
- Linux中重定向和管道介紹Linux
- 快速掌握mongoDB(二)——聚合管道和MapReduceMongoDB
- netty 管道傳遞Netty
- AngularJS 4(五)【管道】AngularJS