進程通信目的:
(1)數(shù)據傳輸:進程間數(shù)據傳輸;
(2)通知事件:一個進程向另一個或一組進程發(fā)送消息,通知某個事件的發(fā)生(如子進程終止時需通知父進程);
(3)資源共享:多個進程共享資源,需要內核提供同步互斥機制;
(4)進程控制:某進程需要控制另一個進程的執(zhí)行(如Debug進程),此時控制進程需要攔截另一個進程的所有陷入、異常、狀態(tài)等。
進行通信分類及方式:
無名管道
特點:(1)半雙工。數(shù)據同一時刻只能單向傳輸;
? ? ? ? ? ?(2)數(shù)據從管道一端寫入,另一端讀出;
? ? ? ? ? ?(3)寫入管道的數(shù)據遵循先進先出;
? ? ? ? ? ?(4)管道非普通文件,不屬于某個文件系統(tǒng),只存在于內存;
? ? ? ? ? ?(5)無名管道只能在具有公共祖先的進程(父子進程、兄弟進程等)之間使用。
(1)pipe函數(shù):創(chuàng)建無名管道
#include<unistd.h>
int pipe(int pipefd[2]);
/*
功能:
創(chuàng)建無名管道。
參數(shù):
pipefd:int型數(shù)組的首地址,存放了管道文件描述符pipefd[0]、pipefd[1]。
pipefd[0]用于讀管道,pipefd[1]用于寫管道。
一般的文件I/O函數(shù)都可用來操作管道(lseek除外)。
返回值:
成功:0
失?。?1
*/
pipe示例:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
int test() {
int fds[2]; // fds[0]用于讀管道,fds[1]用于寫管道
int ret = -1;
// 創(chuàng)建一個無名管道
ret = pipe(fds);
if (-1 == ret) {
perror("pipe");
return 1;
}
printf("讀管道的文件描述符:%d, 寫管道的文件描述符:%d\n", fds[0], fds[1]);
// 關閉文件描述符
close(fds[0]);
close(fds[1]);
return 0;
}
運行結果:
(2)父子進程使用無名管道通信原理:
a)需要在fork之前創(chuàng)建無名管道,然后子進程也有自己的讀寫管道描述符關聯(lián)無名管道;
b)父進程給子進程發(fā)消息:父進程寫管道、子進程讀管道;需要關閉父進程的讀端文件描述符(fds[0])、子進程的寫端文件描述符(fds[1])。 反之類似。
c)管道默認為阻塞,讀不到內容則阻塞等待有內容可讀;可設置為非阻塞。
(3)管道讀寫特性:
case 1:
? ? ? ? a)若寫端打開,管道中無數(shù)據,讀端進程會阻塞;
? ? ? ? b)若寫端打開,管道中有數(shù)據,讀端進程將數(shù)據讀出,下次若無數(shù)據可讀則阻塞;
case 2:
? ? ? ? 若寫端關閉,讀端進程讀取全部內容后,返回0;
case 3:
? ? ? ? 若讀端打開,管道被寫滿,則寫端進程阻塞;
case 4:
? ? ? ? 若讀端關閉,寫端進程收到一個信號,然后退出。
查看管道大小:
(4)父子進程使用無名管道通信示例:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#define SIZE 64
int main(int argc, const char* argv[]) {
int ret = -1;
int fds[2];
pid_t pid = -1;
char buf[SIZE];
// 1. 創(chuàng)建無名管道
ret = pipe(fds);
if (-1 == ret) {
perror("pipe");
return 1;
}
// 2. 創(chuàng)建子進程。需要在創(chuàng)建無名管道之后
pid = fork();
if (-1 == pid) {
perror("fork");
return 1;
}
// 子進程 讀管道
if (0 == pid) {
close(fds[1]); // 關閉寫端
ret = read(fds[0], buf, SIZE); // 讀管道
if (ret < 0) {
perror("read");
exit(-1);
}
printf("子進程讀到的內容:%s\n", buf);
close(fds[0]); // 關閉讀端
exit(0); // 子進程退出
}
// 父進程 寫管道
close(fds[0]); // 關閉讀端
ret = write(fds[1], "ABCDEFG", 7); // 寫管道
if (-1 == ret) {
perror("write");
return 1;
}
printf("父進程寫了%d字節(jié).\n", ret);
close(fds[1]); // 關閉寫端
return 0;
}
運行結果:
(5)fpathconf函數(shù):查看管道緩沖區(qū)
#include<unistd.h>
long fpathconf(int fd, int name);
/*
功能:
通過name查看管道緩沖區(qū)的不同屬性
參數(shù):
fd:讀端或寫端文件描述符
name:
_PC_PIPE_BUF:查看管道緩沖區(qū)大小
_PC_NAME_MAX:文件名字節(jié)數(shù)上限
返回值:
成功:屬性值
失?。?1
*/
fpathconf示例:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
int main(int argc, const char* argv[]) {
int fds[2];
int ret = -1;
ret = pipe(fds);
if (-1 == ret) {
perror("pipe");
return 1;
}
printf("讀端緩沖區(qū)大小:%ld,\n寫端緩沖區(qū)大?。?ld,\n讀端文件名字節(jié)數(shù)上限:%ld,\n寫端文件名字節(jié)數(shù)上限:%ld\n",
fpathconf(fds[0], _PC_PIPE_BUF), fpathconf(fds[1], _PC_PIPE_BUF),
fpathconf(fds[0], _PC_NAME_MAX), fpathconf(fds[1], _PC_NAME_MAX));
return 0;
}
運行結果:
(6)管道讀端緩沖區(qū)設置為非阻塞的方法:
// 獲取讀端緩沖區(qū)原先的狀態(tài)標記flags
int flags = fcntl(fd[0], F_GETFL);
// 設置新狀態(tài)標記flags加入非阻塞狀態(tài)
flags |= O_NONBLOCK;
// 給讀端緩沖區(qū)設置新狀態(tài)標記
fcntl(fd[0], F_SETFL, flags);
讀端設置為非阻塞,若無數(shù)據,讀進程直接返回-1.
讀端以非阻塞的方式讀管道示例:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#define SIZE 64
int main(int argc, const char* argv[]) {
int ret = -1;
int fds[2];
pid_t pid = -1;
char buf[SIZE];
// 1. 創(chuàng)建無名管道
ret = pipe(fds);
if (-1 == ret) {
perror("pipe");
return 1;
}
// 2. 創(chuàng)建子進程。需要在創(chuàng)建無名管道之后
pid = fork();
if (-1 == pid) {
perror("fork");
return 1;
}
// 子進程 讀管道
if (0 == pid) {
close(fds[1]); // 關閉寫端
/*設置讀端非阻塞*/
ret = fcntl(fds[0], F_GETFL); // 獲取讀端緩沖區(qū)狀態(tài)
ret |= O_NONBLOCK; //將讀端緩沖區(qū)加入非阻塞狀態(tài)
fcntl(fds[0], F_SETFL, ret); // 將新狀態(tài)設置進入
ret = read(fds[0], buf, SIZE); // 讀管道
if (ret < 0) {
perror("read");
exit(-1);
}
printf("子進程讀到的內容:%s\n", buf);
close(fds[0]); // 關閉讀端
exit(0); // 子進程退出
}
// 父進程 寫管道
sleep(1);
close(fds[0]); // 關閉讀端
ret = write(fds[1], "ABCDEFG", 7); // 寫管道
if (-1 == ret) {
perror("write");
return 1;
}
printf("父進程寫了%d字節(jié).\n", ret);
close(fds[1]); // 關閉寫端
return 0;
}
運行結果:文章來源:http://www.zghlxwxcb.cn/news/detail-423587.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-423587.html
到了這里,關于Linux進程通信:無名管道的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!