linux-程序間通信
- 1 學習目标
- 2 程序間通信相關概念
-
- 2.1 什麼是程序間通信
- 2.2 程序間通信的方式
- 3 管道-pipe
-
- 3.1管道的概念
- 3.2管道的原理
- 3.3管道的局限性
- 3.4建立管道-pipe函數
- 3.5父子程序使用管道通信
- 3.6 管道練習
- 3.7 管道的讀寫行為
- 3.8 如何設定管道為非阻塞
- 3.9 如何檢視管道緩沖區大小
- 4 FIFO
-
- 4.1 FIFO介紹
- 4.2 建立管道
- 4.3 使用FIFO完成兩個程序通信
- 5 記憶體映射區
-
- 5.1 存儲映射區介紹
- 5.2 mmap函數
- 5.3 munmap函數
- 5.4 mmap注意事項
- 5.5 有關mmap函數的使用總結
- 5.6 mmap函數相關思考題
- 5.7 mmap應用練習
1 學習目标
- 熟練使用pipe進行父子程序間通信
- 熟練使用pipe進行兄弟程序間通信
- 熟練使用fifo進行無血緣關系的程序間通信
- 使用mmap進行有血緣關系的程序間通信
- 使用mmap進行無血緣關系的程序間通信
2 程序間通信相關概念
2.1 什麼是程序間通信
Linux環境下,程序位址空間互相獨立,每個程序各自有不同的使用者位址空間。任何一個程序的全局變量在另一個程序中都看不到,是以程序和程序之間不能互相通路,要交換資料必須通過核心,在核心中開辟一塊緩沖區,程序1把資料從使用者空間拷到核心緩沖區,程序2再從核心緩沖區把資料讀走,核心提供的這種機制稱為程序間通信(IPC,InterProcess Communication)。
2.2 程序間通信的方式
在程序間完成資料傳遞需要借助作業系統提供特殊的方法,如:檔案、管道、信号、共享記憶體、消息隊列、套接字、命名管道等。随着計算機的蓬勃發展,一些方法由于自身設計缺陷被淘汰或者棄用。現今常用的程序間通信方式有:
- 管道 (使用最簡單)
- 信号 (開銷最小)
- 共享映射區 (無血緣關系)
- 本地套接字 (最穩定)
3 管道-pipe
3.1管道的概念
管道是一種最基本的IPC機制,也稱匿名管道,應用于有血緣關系的程序之間,完成資料傳遞。調用pipe函數即可建立一個管道。
有如下特質:
- 管道的本質是一塊核心緩沖區
- 由兩個檔案描述符引用,一個表示讀端,一個表示寫端。
- 規定資料從管道的寫端流入管道,從讀端流出。
- 當兩個程序都終結的時候,管道也自動消失。
- 管道的讀端和寫端預設都是阻塞的。
3.2管道的原理
- 管道的實質是核心緩沖區,内部使用環形隊列實作。
- 預設緩沖區大小為4K,可以使用ulimit -a指令擷取大小。
- 實際操作過程中緩沖區會根據資料壓力做适當調整。
3.3管道的局限性
- 資料一旦被讀走,便不在管道中存在,不可反複讀取。
- 資料隻能在一個方向上流動,若要實作雙向流動,必須使用兩個管道
- 隻能在有血緣關系的程序間使用管道。
3.4建立管道-pipe函數
-
函數作用:
建立一個管道
-
函數原型:
int pipe(int fd[2]);
-
函數參數:
若函數調用成功,fd[0]存放管道的讀端,fd[1]存放管道的寫端
-
傳回值:
成功傳回0;
失敗傳回-1,并設定errno值。
函數調用成功傳回讀端和寫端的檔案描述符,其中fd[0]是讀端,fd[1]是寫端,向管道讀寫資料是通過使用這兩個檔案描述符進行的,讀寫管道的實質是操作核心緩沖區。
管道建立成功以後,建立該管道的程序(父程序)同時掌握着管道的讀端和寫端。如何實作父子程序間通信呢?
3.5父子程序使用管道通信
一個程序在由pipe()建立管道後,一般再fork一個子程序,然後通過管道實作父子程序間的通信(是以也不難推出,隻要兩個程序中存在血緣關系,這裡的血緣關系指的是具有共同的祖先,都可以采用管道方式來進行通信)。父子程序間具有相同的檔案描述符,且指向同一個管道pipe,其他沒有關系的程序不能獲得pipe()産生的兩個檔案描述符,也就不能利用同一個管道進行通信。
第一步:父程序建立管道
第二步:父程序fork出子程序
第三步:父程序關閉fd[0],子程序關閉fd[1]
建立步驟總結:
- 父程序調用pipe函數建立管道,得到兩個檔案描述符fd[0]和fd[1],分别指向管道的讀端和寫端。
- 父程序調用fork建立子程序,那麼子程序也有兩個檔案描述符指向同一管。
- 父程序關閉管道讀端,子程序關閉管道寫端。父程序可以向管道中寫入資料,子程序将管道中的資料讀出,這樣就實作了父子程序間通信。
3.6 管道練習
- 一個程序能否使用管道完成讀寫操作呢?
- 使用管道完成父子程序間通信?
-
父子程序間通信, 實作ps aux | grep bash
使用execlp函數和dup2函數
/*
* @Descripttion: 使用pipe完成ps aux | grep bash
* @version:
* @Author: Lzy
* @Date: 2021-07-21 16:50:31
* @LastEditors: Lzy
* @LastEditTime: 2021-07-21 17:52:46
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
int main(int argc, char **argv)
{
int fd[2];
int ret = pipe(fd);
if (ret < 0)
{
perror("pipe error");
return -1;
}
pid_t pid = fork();
if (pid < 0)
{
perror("fork error");
}
else if (pid > 0)
{
close(fd[0]);
dup2(fd[1], STDOUT_FILENO);
execlp("ps", "ps", "aux", NULL);
perror("excelp error");
wait(NULL);
}
else
{
close(fd[1]);
dup2(fd[0], STDIN_FILENO);
execlp("grep", "grep", "bash", NULL);
perror("execlp error");
}
return 0;
}
-
兄弟程序間通信, 實作ps aux | grep bash
使用execlp函數和dup2函數
父程序要調用waitpid函數完成對子程序的回收
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
int main()
{
int fd[2];
int ret;
pid_t pid;
//建立一個管道
ret = pipe(fd);
if(ret<0)
{
perror("pipe error");
return -1;
}
int i = 0;
int n = 2;
for(i=0; i<n; i++)
{
//建立子程序
pid = fork();
if(pid<0)
{
perror("fork error");
return -1;
}
else if(pid==0)
{
break;
}
}
if(i==n)
{
close(fd[0]);
close(fd[1]);
pid_t wpid;
int status;
while(1)
{
//等待回收子程序
wpid = waitpid(-1, &status, WNOHANG);
if(wpid==0) //沒有子程序退出
{
sleep(1);
continue;
}
else if(wpid==-1) //已經沒有子程序
{
printf("no child is living, wpid==[%d]\n", wpid);
exit(0);
}
else if(wpid>0)
{
if(WIFEXITED(status)) //正常退出
{
printf("child normal exited, status==[%d]\n", WEXITSTATUS(status));
}
else if(WIFSIGNALED(status)) //被信号殺死
{
printf("child killed by signo==[%d]\n", WTERMSIG(status));
}
}
}
}
//第一個子程序
if(i==0)
{
close(fd[0]);
//将标準輸出重定向到管道到寫端
dup2(fd[1], STDOUT_FILENO);
execlp("ps", "ps", "aux", NULL);
perror("execlp error");
close(fd[1]);
}
//第二個子程序
if(i==1)
{
printf("child: fpid==[%d], cpid==[%d]\n", getppid(), getpid());
close(fd[1]);
//将标準輸入重定向到管道到讀端
dup2(fd[0], STDIN_FILENO);
execlp("grep", "grep", "--color", "bash", NULL);
perror("execlp error");
close(fd[0]);
}
return 0;
}
3.7 管道的讀寫行為
- 讀操作
- 有資料:read正常讀,傳回讀出的位元組數
- 無資料:寫端全部關閉:read解除阻塞,傳回0, 相當于讀檔案讀到了尾部;沒有全部關閉:read阻塞。
- 寫操作
- 讀端全部關閉:管道破裂,程序終止, 核心給目前程序發SIGPIPE信号
- 讀端沒全部關閉:緩沖區寫滿了,write阻塞;緩沖區沒有滿,繼續write。
3.8 如何設定管道為非阻塞
預設情況下,管道的讀寫兩端都是阻塞的,若要設定讀或者寫端為非阻塞,則可參考下列三個步驟進行:
第1步:
int flags = fcntl(fd[0], F_GETFL, 0);
第2步:
flag |= O_NONBLOCK;
第3步:
fcntl(fd[0], F_SETFL, flags);
若是讀端設定為非阻塞:
- 寫端沒有關閉,管道中沒有資料可讀,則read傳回-1;
- 寫端沒有關閉,管道中有資料可讀,則read傳回實際讀到的位元組數
- 寫端已經關閉,管道中有資料可讀,則read傳回實際讀到的位元組數
- 寫端已經關閉,管道中沒有資料可讀,則read傳回0
3.9 如何檢視管道緩沖區大小
-
指令
ulimit -a
- 函數
long fpathconf(int fd, int name);
printf("pipe size==[%ld]\n", fpathconf(fd[0], _PC_PIPE_BUF));
printf("pipe size==[%ld]\n", fpathconf(fd[1], _PC_PIPE_BUF));
4 FIFO
4.1 FIFO介紹
FIFO常被稱為命名管道,以區分管道(pipe)。管道(pipe)隻能用于“有血緣關系”的程序間通信。但通過FIFO,不相關的程序也能交換資料。
FIFO是Linux基礎檔案類型中的一種(檔案類型為p,可通過ls -l檢視檔案類型)。但FIFO檔案在磁盤上沒有資料塊,檔案大小為0,僅僅用來辨別核心中一條通道。程序可以打開這個檔案進行read/write,實際上是在讀寫核心緩沖區,這樣就實作了程序間通信。
4.2 建立管道
-
方式1-使用指令 mkfifo
指令格式: mkfifo 管道名
例如:mkfifo myfifo
-
方式2-使用函數
int mkfifo(const char *pathname, mode_t mode);
參數說明和傳回值可以檢視man 3 mkfifo
當建立了一個FIFO,就可以使用open函數打開它,常見的檔案I/O函數都可用于FIFO。如:close、read、write、unlink等。
FIFO嚴格遵循先進先出(first in first out),對FIFO的讀總是從開始處傳回資料,對它們的寫則把資料添加到末尾。它們不支援諸如lseek()等檔案定位操作。
4.3 使用FIFO完成兩個程序通信
- 使用FIFO完成兩個程序通信的示意圖
思路:
- 程序A:
- 建立一個fifo檔案:myfifo
- 調用open函數打開myfifo檔案
- 調用write函數寫入一個字元串如:“hello world”(其實是将資料寫入到了核心緩沖區)
- 調用close函數關閉myfifo檔案
- 程序B:
- 調用open函數打開myfifo檔案
- 調用read函數讀取檔案内容(其實就是從核心中讀取資料)
- 列印顯示讀取的内容
- 調用close函數關閉myfifo檔案
注意:myfifo檔案是在程序A中建立的,如果先啟動程序B會報錯。思考一下如何解決這個問題呢???
程序A寫入資料
/*
* @Descripttion:
* @version:
* @Author: Lzy
* @Date: 2021-07-22 16:54:53
* @LastEditors: Lzy
* @LastEditTime: 2021-07-22 17:33:56
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char **argv)
{
// int access(const char *pathname, int mode);
int ret = access("./myfifo", F_OK);
if (ret == -1)
{
//檔案不存在
// int mkfifo(const char *pathname, mode_t mode);
ret = mkfifo("./myfifo", 0777);
if (ret == -1)
{
perror("mkfifo error:");
return -1;
}
}
int fd = open("./myfifo",O_RDWR);
if (fd == -1){
perror("open error:");
return -1;
}
write(fd,"hello world!\n",sizeof("hello world"));
sleep(20);
close(fd);
return 0;
}
程序B讀取資料
/*
* @Descripttion:
* @version:
* @Author: Lzy
* @Date: 2021-07-22 16:54:53
* @LastEditors: Lzy
* @LastEditTime: 2021-07-22 18:01:43
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char **argv)
{
// int access(const char *pathname, int mode);
int ret = access("./myfifo", F_OK);
if (ret == -1)
{
//檔案不存在
// int mkfifo(const char *pathname, mode_t mode);
ret = mkfifo("./myfifo", 0777);
if (ret == -1)
{
perror("mkfifo error:");
return -1;
}
}
int fd = open("./myfifo",O_RDWR);
if (fd == -1){
perror("open error:");
return -1;
}
char str[20];
memset(str,0,sizeof(str));
read(fd,str,sizeof(str));
printf("read is %s",str);
close(fd);
return 0;
}
5 記憶體映射區
5.1 存儲映射區介紹
存儲映射I/O (Memory-mapped I/O) 使一個磁盤檔案與存儲空間中的一個緩沖區相映射。從緩沖區中取資料,就相當于讀檔案中的相應位元組;将資料寫入緩沖區,則會将資料寫入檔案。這樣,就可在不使用read和write函數的情況下,使用位址(指針)完成I/O操作。
使用存儲映射這種方法,首先應通知核心,将一個指定檔案映射到存儲區域中。這個映射工作可以通過mmap函數來實作。
5.2 mmap函數
-
函數作用:
建立存儲映射區
-
函數原型
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
-
函數傳回值:
成功:傳回建立的映射區首位址;
失敗:MAP_FAILED宏
- 參數:
- addr: 指定映射的起始位址, 通常設為NULL, 由系統指定
- length:映射到記憶體的檔案長度
-
prot: 映射區的保護方式, 最常用的:
讀:PROT_READ
寫:PROT_WRITE
讀寫:PROT_READ | PROT_WRITE
-
flags: 映射區的特性, 可以是
MAP_SHARED: 寫入映射區的資料會寫回檔案, 且允許其他映射該檔案的程序共享。
MAP_PRIVATE: 對映射區的寫入操作會産生一個映射區的複制(copy-on-write), 對此區域所做的修改不會寫回原檔案。
- fd:由open傳回的檔案描述符, 代表要映射的檔案。
- offset:以檔案開始處的偏移量, 必須是4k的整數倍, 通常為0, 表示從檔案頭開始映射。
5.3 munmap函數
-
函數作用:
釋放由mmap函數建立的存儲映射區
-
函數原型:
int munmap(void *addr, size_t length);
-
傳回值:
成功:傳回0
失敗:傳回-1,設定errno值
- 函數參數:
- addr:調用mmap函數成功傳回的映射區首位址
- length:映射區大小(mmap函數的第二個參數)
5.4 mmap注意事項
- 建立映射區的過程中,隐含着一次對映射檔案的讀操作,将檔案内容讀取到映射區
- 當MAP_SHARED時,要求:映射區的權限應 <=檔案打開的權限(出于對映射區的保護)。而MAP_PRIVATE則無所謂,因為mmap中的權限是對記憶體的限制。
- 映射區的釋放與檔案關閉無關,隻要映射建立成功,檔案可以立即關閉。
- 特别注意,當映射檔案大小為0時,不能建立映射區。是以,用于映射的檔案必須要有實際大小;mmap使用時常常會出現總線錯誤,通常是由于共享檔案存儲空間大小引起的。
- munmap傳入的位址一定是mmap的傳回位址。堅決杜絕指針++操作。
- 檔案偏移量必須為0或者4K的整數倍
- mmap建立映射區出錯機率非常高,一定要檢查傳回值,確定映射區建立成功再進行後續操作。
5.5 有關mmap函數的使用總結
- 第一個參數寫成NULL
- 第二個參數要映射的檔案大小 > 0
- 第三個參數:PROT_READ 、PROT_WRITE
- 第四個參數:MAP_SHARED 或者 MAP_PRIVATE
- 第五個參數:打開的檔案對應的檔案描述符
- 第六個參數:4k的整數倍
5.6 mmap函數相關思考題
- 可以open的時候O_CREAT一個新檔案來建立映射區嗎?
- 如果open時O_RDONLY, mmap時PROT參數指定PROT_READ|PROT_WRITE會怎樣?
- mmap映射完成之後, 檔案描述符關閉,對mmap映射有沒有影響?
- 如果檔案偏移量為1000會怎樣?
- 對mem越界操作會怎樣?
- 如果mem++,munmap可否成功?
- mmap什麼情況下會調用失敗?
- 如果不檢測mmap的傳回值,會怎樣?
5.7 mmap應用練習
- 練習1:使用mmap完成對檔案的讀寫操作
/*
* @Descripttion: 使用mmap完成對檔案的讀寫操作,傳入第一個參數為檔案名,若沒傳入則使用預設檔案"test.log"。
* @version:
* @Author: Lzy
* @Date: 2021-07-22 14:36:29
* @LastEditors: Lzy
* @LastEditTime: 2021-07-22 15:02:25
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/wait.h>
int main(int argc, char **argv)
{
int fd = 0;
char *filename = NULL;
if (argc > 1)
{
//傳入檔案名,使用提供檔案
filename = argv[1];
}
else
{
//使用預設檔案名
filename = "test.log";
}
printf("%s\n", filename);
// int access(const char *pathname, int mode);
fd = open(filename, O_RDWR | O_CREAT, 0777);
if (fd == -1)
{
perror("open error:");
}
// ssize_t write(int fd, const void *buf, size_t count);
//使檔案大小大于0,mmap函數要求
write(fd, "1", strlen("1"));
//擷取檔案大小
struct stat statbuf;
int ret = stat(filename, &statbuf);
if (ret < 0)
{
perror("stat error:");
}
// void *mmap(void *addr, size_t length, int prot, int flags,
// int fd, off_t offset);
void *addr = mmap(NULL, statbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED)
{
perror("mmap error");
return -1;
}
memcpy(addr, "hello world!", strlen("hello world!"));
char *str = (char *)addr;
printf("read is [%s]\n", str);
return 0;
}
- 練習:2:使用mmap完成父子程序間通信
- 圖解說明
- 思路
- 調用mmap函數建立存儲映射區,傳回映射區首位址ptr
- 調用fork函數建立子程序,子程序也擁有了映射區首位址
- 父子程序可以通過映射區首位址指針ptr完成通信
- 調用munmap函數釋放存儲映射區
/*
* @Descripttion: 使用mmap完成父子程序間通信,傳入第一個參數為檔案名,若沒傳入則使用預設檔案"test.log"。
* @version:
* @Author: Lzy
* @Date: 2021-07-22 14:36:29
* @LastEditors: Lzy
* @LastEditTime: 2021-07-22 16:46:01
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/wait.h>
int main(int argc, char **argv)
{
int fd = 0;
char *filename = NULL;
if (argc > 1)
{
//傳入檔案名,使用提供檔案
filename = argv[1];
}
else
{
//使用預設檔案名
filename = "test.log";
}
printf("%s\n", filename);
// int access(const char *pathname, int mode);
fd = open(filename, O_RDWR | O_CREAT, 0777);
if (fd == -1)
{
perror("open error:");
}
// ssize_t write(int fd, const void *buf, size_t count);
//使檔案大小大于0,mmap函數要求
write(fd, "1", strlen("1"));
//擷取檔案大小
struct stat statbuf;
int ret = stat(filename, &statbuf);
if (ret < 0)
{
perror("stat error:");
}
// void *mmap(void *addr, size_t length, int prot, int flags,
// int fd, off_t offset);
void *addr = mmap(NULL, statbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED)
{
perror("mmap error");
return -1;
}
pid_t pid = fork();
if(pid < 0){
perror("fork error:");
}else if(pid > 0){
memcpy(addr,"hello world!",strlen("hello world!"));
wait(NULL);
munmap(addr,statbuf.st_size);
}else if(pid == 0){
char str [20];
memset(str,0,sizeof(str));
memcpy(str,addr,strlen(addr));
printf("read is [%s]\n",str);
}
return 0;
}
-
練習3:使用mmap完成沒有血緣關系的程序間通
思路:兩個程序都打開相同的檔案,然後調用mmap函數建立存儲映射區,這樣兩個程序共享同一個存儲映射區。
程序一寫檔案:
/*
* @Descripttion: 使用mmap完成沒有血緣關系的程序間通,傳入第一個參數為檔案名,若沒傳入則使用預設檔案"test.log"。
* @version:
* @Author: Lzy
* @Date: 2021-07-22 14:36:29
* @LastEditors: Lzy
* @LastEditTime: 2021-07-22 16:52:25
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/wait.h>
int main(int argc, char **argv)
{
int fd = 0;
char *filename = NULL;
if (argc > 1)
{
//傳入檔案名,使用提供檔案
filename = argv[1];
}
else
{
//使用預設檔案名
filename = "test.log";
}
printf("%s\n", filename);
// int access(const char *pathname, int mode);
fd = open(filename, O_RDWR | O_CREAT, 0777);
if (fd == -1)
{
perror("open error:");
}
// ssize_t write(int fd, const void *buf, size_t count);
//使檔案大小大于0,mmap函數要求
write(fd, "1", strlen("1"));
//擷取檔案大小
struct stat statbuf;
int ret = stat(filename, &statbuf);
if (ret < 0)
{
perror("stat error:");
}
// void *mmap(void *addr, size_t length, int prot, int flags,
// int fd, off_t offset);
void *addr = mmap(NULL, statbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED)
{
perror("mmap error");
return -1;
}
char str [20];
memset(str,0,sizeof(str));
memcpy(str,addr,strlen(addr));
printf("read is [%s]\n",str);
return 0;
}
程序2讀
/*
* @Descripttion: 使用mmap完成沒有血緣關系的程序間通,傳入第一個參數為檔案名,若沒傳入則使用預設檔案"test.log"。
* @version:
* @Author: Lzy
* @Date: 2021-07-22 14:36:29
* @LastEditors: Lzy
* @LastEditTime: 2021-07-22 16:52:25
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/wait.h>
int main(int argc, char **argv)
{
int fd = 0;
char *filename = NULL;
if (argc > 1)
{
//傳入檔案名,使用提供檔案
filename = argv[1];
}
else
{
//使用預設檔案名
filename = "test.log";
}
printf("%s\n", filename);
// int access(const char *pathname, int mode);
fd = open(filename, O_RDWR | O_CREAT, 0777);
if (fd == -1)
{
perror("open error:");
}
// ssize_t write(int fd, const void *buf, size_t count);
//使檔案大小大于0,mmap函數要求
write(fd, "1", strlen("1"));
//擷取檔案大小
struct stat statbuf;
int ret = stat(filename, &statbuf);
if (ret < 0)
{
perror("stat error:");
}
// void *mmap(void *addr, size_t length, int prot, int flags,
// int fd, off_t offset);
void *addr = mmap(NULL, statbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED)
{
perror("mmap error");
return -1;
}
char str [20];
memset(str,0,sizeof(str));
memcpy(str,addr,strlen(addr));
printf("read is [%s]\n",str);
return 0;
}
- 練習4:使用mmap函數建立匿名映射:mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);(父子程序分享)
/*
* @Descripttion: 測試mmap匿名映射進行親緣關系通信(推薦)
* @version:
* @Author: Lzy
* @Date: 2021-07-22 10:43:24
* @LastEditors: Lzy
* @LastEditTime: 2021-07-22 14:34:15
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/wait.h>
int main(int argc, char **argv)
{
// void *mmap(void *addr, size_t length, int prot, int flags,
// int fd, off_t offset);
void *addr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (addr == MAP_FAILED)
{
perror("mmap error");
return -1;
}
pid_t pid = fork();
if (pid < 0)
{
perror("fork error");
return -1;
}
else if (pid > 0)
{
memcpy(addr, "hello world!", strlen("hello world!"));
wait(NULL);
}
else if (pid == 0)
{
char *p = (char *)addr;
printf("%s", p);
}
return 0;
}