LINUX 64位下运行32位程序加载和读取大数据段共享内存

时间:2022-04-15 03:33:09

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;
}