一、進程的間通信的原理
進程間交換數據必須通過內核,在內核中開闢一塊緩衝區,進程1把數據空間拷貝到內核緩衝區,進程2再從內核緩衝區把數據讀走。這樣就實現了進程間通信。
二、進程通信的進制--管道(pipe)
調用 pipe(int filedes[2])函數在內存中開闢的空間稱爲管道,它一端讀數據一端寫數據,通過filedes傳出給用戶程序的兩個描述符,filedes[0]指向讀端,filedes[1]指向寫端。所以通過read(filedes[0);或者write(filedes),來從管道讀或寫文件。
三、 用管道實現進程通信的方法
(1)父進程創建管道,得到兩個文件描述符指向管道的兩端、
(2)父進程調用fork()創建子進程,那麼子進程也有兩個文件描述符指向管道的兩端。
(3)父進程關閉寫端,子進程關閉讀端,子進程往管道寫,父進程讀,管道是用環形隊列實現的,數據從寫端寫入,讀端讀出,這樣就實現了進程通信
--代碼-----
#include<stdio.h> #include<unistd.h> int main() { int _pipe[2]; int ret=pipe(_pipe); if(ret < 0) { printf(" pipe()"); return 1; } pid_t id=fork(); if(id < 0) { printf("fork()"); return 2; } else if(id==0) { close(_pipe[0]); char buf[]="hello world"; int count=10; while(count) { sleep(1); ssize_t _size=write(_pipe[1],buf,sizeof(buf)); if(_size < 0) { printf("write()"); return 3; } count--; } }else { close(_pipe[1]); char buf[1024]; int i=0; while(i++<10) { ssize_t _size=read(_pipe[0],buf,sizeof(buf)); if(_size >0) { buf[_size]='\n'; printf("%s\n",buf); } else { printf("child is empty or exit") ; break; } } } return 0; }
運行結果:
四、管道的限制
兩個進程用一個管道只能實現單進程通信,一個寫一個讀,不能同時進行讀寫,如果要讓父進程寫,子進程讀,就必須重新另開一個管道。管道的讀寫端是通過打開的文件描述符來傳遞的,所以兩個進程必須從父進程那裏繼承文件描述符。只有兩個進程都能訪問同一管道時,他們才能通信。
五、管道的4種特殊情況
(1)如果指向管道寫端的文件描述符都關閉了,但是仍有進程從管道的讀端讀數據,那麼管道中剩餘的數據被讀完後,再次read 就會返回0。
(2)如果有指向管道寫端的文件描述符沒關閉,而持有管道寫端的進程也沒有向管道中寫數據,這時有進程從管道讀端讀數據,那麼管道中剩餘的數據都被讀取後,再次read會阻塞,直到管道中有數據可讀了纔讀取數據並返回。
(3)如果所有指向管道讀端的文件描述符都關閉了,這時有進程向管道的寫端write,那麼該進程會收到信號SIGPIPE,通常會導致進程異常終止。
(4)如果所有指向管道讀端的文件描述符沒關閉,但是也不從管道中讀取數據,這是如果進程向管道寫端寫數據,那麼在管道被寫滿時,再寫的話就會被阻塞,直到管道中有了空位置才寫入數據並返回。
管道的缺點在於是沒有名字,因此,只能用於有親緣關係的進程之間進行通信,爲了解決這個問題,又引入了命名管道(FIFO),命名管道提供了路徑名與之關聯,以FIFO的文件形式存儲於文件系統中,所以只要訪問該路勁,就能實現進程間的通信。FIFO總是按照先進先出的原則工作,第一個被寫入的先出來。
一、命名管道的創建
用mkfifo函數來創建FIFO
int mkfifo(const char *path,mode_t mode);
二、命名管道的使用方法
先調用open()將其打開,要以只讀的方式打開,以寫的方式打開寫入(O_WRONLY)
三、命名管道的程序代碼:
client端
#include<stdio.h> #include<error.h> #include<stdlib.h> #include<string.h> #include<fcntl.h> #include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #define _PATH_ "./.tem" int main() { int fd=open(_PATH_,O_RDONLY); if(fd<0) { printf("open error"); } char buf[1024]; memset(buf,'\0',sizeof(buf)); while(1) { int ret =read(fd,buf,sizeof(buf)); if(ret>0) { buf[ret]='\n'; printf("serve said:%s\n",buf); } } close(fd); return 0; }
serve端
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<fcntl.h> #include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #define _PATH_ "./.tem" int main() { umask(0); int ret = mkfifo(_PATH_,S_IFIFO |0666) ; if(ret<0) { printf("mkfifo error\n"); return 1; } int fd=open(_PATH_,O_WRONLY); if(fd<0) { printf("open error"); } char buf[1024]; memset(buf,'\0',sizeof(buf)); while(1) { printf("please iput\n"); scanf("%s",buf); int ret =write(fd,buf,strlen(buf)+1); if(ret<0) { printf("write error\n"); break; } } close(fd); return 0; }
運行結果: