進程間的通信就像兩人的交流,需要一個“公共場所”常見的有1、內核 2、內存 3、磁盤。
mmap
- 用途:進程間的通信
- 使用原理:把磁盤的一個空間映射到內存中,如下圖所示
- 函數:void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
- 參數解析
- 參數1:希望在內存的哪個位置(即內存地址),傳NULL,由系統自動找一塊內存空間。一般都寫NULL
- 參數2:請內存長度(可以使用lseek函數來測試文件大小)
-
參數3:prot頁面屬性(映射到內存的這一段的權限)
- 參數4:狀態標誌,有兩種:共享映射MAP_SHARED 和 私有映射MAP_PRIVATE
- 共享映射MAP_SHARED:多個進程對同一個文件的映射是共享的,一個進程對映射的內存做了修改,另一個進程也會看到這種變化。 (即,我這個進程修改了一個地方,其他進程也看得到)
- 私有映射MAP_PRIVATE:多個進程對同一個文件的映射不是共享的,一個進程對映射的內存做了修改,另一個進程並不會看到這種變化,也不會真的寫到文件中去。
- 參數5:文件操作符
- 返回值:如果mmap成功則返回映射首地址,如果出錯則返回常數MAP_FAILED
mmap的注意事項:
1、用於進程之間通信,一般設計成結構體,用於傳輸數據
2、進程間通信,一般設計成臨時文件(讀完刪除使用unlink)
3、當有總線出錯,優先查看共享文件是否有存儲空間
4、如果段出錯可能是使用到了,還沒創建的文件(或者是不存在的文件)
示例文件
寫文件端
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#define MAPLEN 0x1000 //這個我來定義文件的大小,一會要映射到內存
//定義一個學生的結構體
struct STU
{
int ID;
char name[64];
char sex;
};
//定義一個函數,專門來輸出進程執行時的錯誤
void sys_err(char *str,int exitno)
{
perror(str);
exit(exitno);
}
/*
你要先要創建一個hello文件,不然一會執行的時候會報段出錯
使用mmap來修改文件信息
*/
//文件寫成傳參的形式
int main(int argc,char *argv[])
{
//創建一個文件結構體變量
struct STU *mm;
int fd,i=0;
if(argc < 2)
{
printf("enter your name\n");
exit(1);
}
//執行時輸入的文件名,會在這裏打開
fd = open(argv[1],O_RDWR|O_CREAT,0777);
//如果打開失敗
if(fd<0)
{
//報錯
sys_err("open",1);
}
//寫入一個“\0”,來擴展文件,讓文件由存儲空間,不寫這下面兩個if會報總線錯誤
if(lseek(fd,MAPLEN-1,SEEK_SET)<0)
{
sys_err("mmsp",3);
}
if(write(fd,"\0",1)<0)
{
sys_err("write",4);
}
//
mm = mmap(NULL,MAPLEN,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(mm == MAP_FAILED)
{
sys_err("mmsp",2);
}
close(fd);
while(1)
{
mm->ID = i;
sprintf(mm->name,"zhaozhao - %d",i++);
if(i%2 == 0)
{
mm->sex = 'm';
}
else
{
mm->sex = 'w';
}
sleep(1);
}
//關閉映射
munmap(mm,MAPLEN);
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>
#include <sys/mman.h>
#define MAPLEN 0x1000
struct STU
{
int ID;
char name[64];
char sex;
};
void sys_err(char *str,int exitno)
{
perror(str);
exit(exitno);
}
int main(int argc,char *argv[])
{
struct STU *mm;
int fd,i=0;
if(argc < 2)
{
printf("enter your name\n");
exit(1);
}
//打開文件,只讀模式
fd = open(argv[1],O_RDWR);
if(fd < 0)
{
sys_err("open",1);
}
mm = mmap(NULL,MAPLEN,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(mm == MAP_FAILED)
{
sys_err("mmsp",2);
}
close(fd);
//讀完刪除文件,防止創建多個文件
nulink(argv[1]);
while(1)
{
printf("%d\n",mm->ID);
printf("%s\n",mm->name);
printf("%c\n",mm->sex);
sleep(1);
}
//關閉
munmap(mm,MAPLEN);
return 0;
}
在寫端執行文件的的時候,輸入文件名稱(沒有創建過的文件),在執行讀端的時候輸入參數(前面創建的文件名稱)這樣在終端上就能看見讀取的數據。