LINUX 64位下运行32位程序加载和读取大数据段共享内存
1. 查看当前机器共享内存
1073741824 = 1024 * 1024 * 1024
[root@six shm]# ipcs
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 0 gdm 600 393216 2 dest
0x00000000 32769 gdm 600 393216 2 dest
0x00000000 65538 gdm 600 393216 2 dest
------ Semaphore Arrays --------
key semid owner perms nsems
0x00000000 0 root 600 1
0x00000000 32769 root 600 1
0x00000000 65538 apache 600 1
0x00000000 98307 apache 600 1
0x00000000 131076 apache 600 1
------ Message Queues --------
key msqid owner perms used-bytes messages
共享内存无我们加载的数据,正常。
2 修改需要被加载的文件,指定文件任意位置(1G)修改为随机指定的内容
[root@six shm]# ./modifyfile bigdatafile.dat 1073741824 ABCD1234567890END
read content=ABCD1234567890END,17
3 把大文件bigdatafile.dat(1.11G)加载到共享内存,一个进程一次加载两个,共加载3次
[root@six shm]# ./fileload mykey1 mykey2 bigdatafile.dat
Usage: mykey1 KeyFile
e.g. srcfile:bigdatafile.dat
Key generated by ftok: 0x64030017
shaddr:0xb0109000,length:1198011173
Usage: mykey2 KeyFile
e.g. srcfile:bigdatafile.dat
Key generated by ftok: 0x64030018
shaddr:0x68a85000,length:1198011173
[root@six shm]# ./fileload mykey3 mykey4 bigdatafile.dat
Usage: mykey3 KeyFile
e.g. srcfile:bigdatafile.dat
Key generated by ftok: 0x6403000d
shaddr:0xb0134000,length:1198011173
Usage: mykey4 KeyFile
e.g. srcfile:bigdatafile.dat
Key generated by ftok: 0x6403000e
shaddr:0x68ab0000,length:1198011173
[root@six shm]# ./fileload mykey5 mykey6 bigdatafile.dat
Usage: mykey5 KeyFile
e.g. srcfile:bigdatafile.dat
Key generated by ftok: 0x6403001b
shaddr:0xb014b000,length:1198011173
Usage: mykey6 KeyFile
e.g. srcfile:bigdatafile.dat
Key generated by ftok: 0x6403001c
shaddr:0x68ac7000,length:1198011173
4 加载完成,查看有 6.6G的共享内存申请
[root@six shm]# ipcs
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 0 gdm 600 393216 2 dest
0x00000000 32769 gdm 600 393216 2 dest
0x00000000 65538 gdm 600 393216 2 dest
0x64030017 589827 root 0 1198011173 0
0x64030018 622596 root 0 1198011173 0
0x6403000d 655365 root 0 1198011173 0
0x6403000e 688134 root 0 1198011173 0
0x6403001b 720903 root 0 1198011173 0
0x6403001c 753672 root 0 1198011173 0
------ Semaphore Arrays --------
key semid owner perms nsems
0x00000000 0 root 600 1
0x00000000 32769 root 600 1
0x00000000 65538 apache 600 1
0x00000000 98307 apache 600 1
0x00000000 131076 apache 600 1
------ Message Queues --------
key msqid owner perms used-bytes messages
5 根据设定偏移量多次组合读取共享内存里面的数据,验证是否一致,结论:和修改的一致。
[root@six shm]# ./memread mykey1 mykey2 1073741824 15
Key generated by ftok: 0x64030017
buff:ABCD1234567890E
Key generated by ftok: 0x64030018
buff:ABCD1234567890E
[root@six shm]# ./memread mykey1 mykey2 1073741824 10
Key generated by ftok: 0x64030017
buff:ABCD123456
Key generated by ftok: 0x64030018
buff:ABCD123456
[root@six shm]# ./memread mykey1 mykey6 1073741824 17
Key generated by ftok: 0x64030017
buff:ABCD1234567890END
Key generated by ftok: 0x6403001c
buff:ABCD1234567890END
[root@six shm]# ./memread mykey1 mykey2 1073741827 14
Key generated by ftok: 0x64030017
buff:D1234567890END
Key generated by ftok: 0x64030018
buff:D1234567890END
[root@six shm]# ./memread mykey3 mykey5 1073741825 10
Key generated by ftok: 0x6403000d
buff:BCD1234567
Key generated by ftok: 0x6403001b
buff:BCD1234567
6 测试环境
测试程序在LINUX 32位开发机编译完成,运行验证在LINUX 64 上通过。
7. fileload.c 代码
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <stdlib.h>
#define PROJ_ID 100
const char * loadfile(char *keyfile, char* srcfile)
{
printf("Usage: %s KeyFile\n e.g. srcfile:%s\n", keyfile, srcfile);
key_t key = ftok(keyfile, PROJ_ID);
printf("Key generated by ftok: 0x%x\n",key);
FILE * fp = fopen(srcfile,"rb");
if(fp == NULL)
{
printf("open file fail\n");
return NULL;
}
fseek(fp,0,SEEK_END);
size_t length = ftell(fp);
//get share memory
int shmid = shmget(key,length,IPC_CREAT|IPC_EXCL);
if(shmid < 0)
{
fclose(fp);
perror("shmget fail");
return NULL;
}
void *shmaddr = (char *)shmat(shmid,0,0);
if(shmaddr == (char *)(-1))
{
fclose(fp);
perror("shmat fail");
return NULL;
}
#define LOADBUFF 1024 * 8
fseek(fp,0,SEEK_SET);
size_t count = length/LOADBUFF;
size_t offset = 0,i = 0;
for(i = 0;i < count;++i)
{
char buff[LOADBUFF] = {0};
size_t onceread = 0;
onceread = fread(buff,1,LOADBUFF,fp);
if(onceread <= 0 )
{
if(ferror(fp) > 0)
{
fclose(fp);
shmdt(shmaddr);
shmctl(shmid,IPC_RMID,0);
printf("fread fail,error\n");
return NULL;
}
}
else
{
memcpy(shmaddr + offset,buff,onceread);
offset += onceread;
}
}
fclose(fp);
printf("shaddr:%p,length:%u\n",shmaddr,length);
/*
if(0 > shmdt(shmaddr))
{
free(buff);
perror("shmdt fail");
return 5;
}
*/
return shmaddr;
}
int main(int argc, char* argv[])
{
if (argc != 4 )
{
printf("Usage: %s KeyFile\n e.g. %s /tmp/mykeyfile\n", argv[0], argv[0]);
return 0;
}
loadfile(argv[1],argv[3]);
loadfile(argv[2],argv[3]);
return 0;
}
8. modifyfile.c 代码
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <stdlib.h>
#define PROJ_ID 100
const char * modifyfile(char *srcfile, size_t offset,char* content)
{
int fp = open(srcfile,O_WRONLY);
if(fp == -1)
{
perror("open file fail\n");
return NULL;
}
size_t length = strlen(content);
lseek(fp,offset,SEEK_SET);
if(length != write(fp,content,length))
{
perror("modify fail");
close(fp);
return NULL;
}
close(fp);
fp = open(srcfile,O_RDONLY);
char buff[8192] = {0};
lseek(fp,offset,SEEK_SET);
length = read(fp,buff,length);
printf("read content=%s,%u\n",buff,length);
close(fp);
return NULL;
}
int main(int argc, char* argv[])
{
if (argc != 4 )
{
printf("Usage: %s KeyFile\n e.g. %s /tmp/mykeyfile\n", argv[0], argv[0]);
return 0;
}
modifyfile(argv[1],atoi(argv[2]),argv[3]);
return 0;
}
9. memread.c 代码
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <stdlib.h>
#define PROJ_ID 100
int readsharememory(char *keyfile,size_t offset,size_t length)
{
char buff[8192] = {0};
if(sizeof(buff) < length)
{
printf("length too length\n");
return 1;
}
key_t key = ftok(keyfile, PROJ_ID);
printf("Key generated by ftok: 0x%x\n",key);
int shmid = shmget(key,0,IPC_CREAT);
if(shmid < 0)
{
perror("shmget fail");
return 4;
}
char *shmaddr = (char *)shmat(shmid,0,SHM_RDONLY);
if(shmaddr == (char *)(-1))
{
perror("shmat fail");
return 5;
}
memcpy(buff,shmaddr + offset,length);
if(0 > shmdt(shmaddr))
{
perror("shmdt fail");
return 5;
}
printf("buff:%s\n",buff);
return 0;
}
int main(int argc, char* argv[])
{
if (argc != 5 )
{
printf("Usage: %s KeyFile\n e.g. %s /tmp/mykeyfile\n", argv[0], argv[0]);
return 0;
}
readsharememory(argv[1],atoi(argv[3]),atoi(argv[4]));
readsharememory(argv[2],atoi(argv[3]),atoi(argv[4]));
return 0;
}
10. share_ctl.c 代码,用于管理共享内存
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#define PROJ_ID 100
int delsharememory(char *keyfile)
{
printf("Usage: %s KeyFile\n", keyfile);
key_t key = ftok(keyfile, PROJ_ID);
printf("Key generated by ftok: 0x%x\n",key);
int shmid = shmget(key,0,IPC_CREAT);
if(shmid < 0)
{
perror("shmget fail");
return 4;
}
if(-1 == shmctl(shmid,IPC_RMID,0))
{
perror("shctl del fail");
return 5;
}
return 0;
}
int getsharememory(char *keyfile)
{
printf("Usage: %s KeyFile\n", keyfile);
key_t key = ftok(keyfile, PROJ_ID);
printf("Key generated by ftok: 0x%x\n",key);
int shmid = shmget(key,0,IPC_CREAT);
if(shmid < 0)
{
perror("shmget fail");
return 4;
}
struct shmid_ds buf;
if(-1 == shmctl(shmid,IPC_STAT,&buf))
{
perror("shctl del fail");
return 5;
}
printf("shm_segsz =%d bytes\n", buf.shm_segsz);
printf("parent pid=%d, shm_cpid = %d \n",getppid(),buf.shm_cpid);
printf("chlid pid=%d, shm_lpid = %d \n",getpid(),buf.shm_lpid);
return 0;
}
int main(int argc, char* argv[])
{
if (argc != 3 )
{
printf("Usage: %s KeyFile CMD(SHOW OR DEL)\n e.g. %s /tmp/mykeyfile\n", argv[0], argv[0]);
return 0;
}
if(strcmp(argv[2],"SHOW") == 0)
{
getsharememory(argv[1]);
}
if(strcmp(argv[2],"DEL") == 0)
{
delsharememory(argv[1]);
}
return 0;
}
11. ftok.c 用于创建共享内存
#include <stdio.h>
#include <sys/ipc.h>
#define PROJ_ID 100
int main(int argc, char* argv[])
{
if (argc !=2 )
{
printf("Usage: %s KeyFile\n e.g. %s /tmp/mykeyfile\n", argv[0], argv[0]);
return 0;
}
printf("Key generated by ftok: 0x%x\n", ftok(argv[1], PROJ_ID));
return 0;
}
12. 测试准备
创建6个key 文件
touch mykey1
touch mykey2
touch mykey3
touch mykey4
touch mykey5
touch mykey6
准备一个大数据文件(1G),名字命名为 : bigdatafile.dat
就可以按上面的步骤测试了。
13. 结论,只要 32 位程序不突破4G的进程最大地址空间,可以挂接其他的任何文件,任何共享
内存区域,和mmap 类似。
14. 公共文件(shm_file.h)
#ifndef _C_LOADFILE_INCLUDE_H_
#define _C_LOADFILE_INCLUDE_H_
//根据文件名构造共享内存段,把文件内容加载到共享内存,返回共享内存首地址
const char * loadfile2shm(const char * filename);
//根据文件名获取到共享内存首地址(只读)
const char * getaddressbyname(const char * filename);
#endif
15. 公共文件(shm_file.c)
#include <assert.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include "shm_file.h"
#define KEYSUFFIX ".key"
#define PROJ_ID 100
#define LOADBUFF 1024 * 8
const char * loadfile2shm(const char * filename)
{
assert(filename != NULL);
char *shmaddr = NULL;
char keyfile[255] = {0};
snprintf(keyfile,sizeof(keyfile) - 1,"%s%s",filename,KEYSUFFIX);
if(0 != access(keyfile,F_OK|R_OK) || 0 != access(filename,F_OK|R_OK))
{
return shmaddr;
}
key_t key = -1;
if(-1 == (key = ftok(keyfile, PROJ_ID)))
{
return shmaddr;
}
FILE * fp = fopen(filename,"rb");
if(fp == NULL)
{
return shmaddr;
}
fseek(fp,0,SEEK_END);
size_t length = 0;
if(0 >= (length = ftell(fp)))
{
fclose(fp);
//perror("shmget fail");
return shmaddr;
}
//get share memory
int shmid = shmget(key,length,IPC_CREAT|IPC_EXCL|0600);
if(shmid < 0)
{
fclose(fp);
//perror("shmget fail");
return shmaddr;
}
//写打开,地址OS动态分配
shmaddr = (char *)shmat(shmid,0,0);
if(shmaddr == (char *)(-1))
{
fclose(fp);
//perror("shmat fail");
return shmaddr;
}
fseek(fp,0,SEEK_SET);
size_t total = 0,offset = 0,i = 0;
total = length/LOADBUFF + 1;
for(i = 0;i < total;++i)
{
char buff[LOADBUFF] = {0};
size_t onceread = 0;
onceread = fread(buff,1,LOADBUFF,fp);
if(onceread <= 0 )
{
if(ferror(fp) > 0)
{
fclose(fp);
shmdt(shmaddr);
shmctl(shmid,IPC_RMID,0);
shmaddr = NULL;
//printf("fread fail,error\n");
return shmaddr;
}
else
{
//feof
}
}
else
{
memcpy(shmaddr + offset,buff,onceread);
offset += onceread;
}
}
fclose(fp);
return shmaddr;
}
const char * getaddressbyname(const char * filename)
{
assert(filename != NULL);
char *shmaddr = NULL;
char keyfile[255] = {0};
snprintf(keyfile,sizeof(keyfile) - 1,"%s%s",filename,KEYSUFFIX);
if(0 != access(keyfile,F_OK|R_OK))
{
return shmaddr;
}
key_t key = -1;
if(-1 == (key = ftok(keyfile, PROJ_ID)))
{
return shmaddr;
}
int shmid = shmget(key,0,IPC_CREAT);
if(shmid < 0)
{
//perror("shmget fail");
return shmaddr;
}
shmaddr = (char *)shmat(shmid,0,SHM_RDONLY);
if(shmaddr == (char *)(-1))
{
//perror("shmat fail");
return shmaddr;
}
return shmaddr;
}