具有共享内存和文件作为数据库的 IPC V 客户端/服务器应用程序,用 C 编写

Posted

技术标签:

【中文标题】具有共享内存和文件作为数据库的 IPC V 客户端/服务器应用程序,用 C 编写【英文标题】:IPC V client/server application with shared memory and a file as database, written on C 【发布时间】:2017-10-26 11:54:14 【问题描述】:

我仍然无法解决这个问题...我有一个使用共享内存作为通信方式的客户端/服务器应用程序的实现。但是,我正在尝试使用一个本地文件作为服务器端的数据库。我猜它是这样的: - 当 客户端 需要某些东西时,他会向 服务器 发出请求(比如说,“如果数据库中有 John,请打印我 John 的名字”。 服务器然后搜索数据库并返回John的字符序列,显然他的客户端编号为123456789,然后客户端打印它。真正的问题发生在客户端尝试阅读此内容 - 我无法理解他必须如何从服务器获取信息并随意使用它。

目前我正在使用临时文件作为数据库,但我什至无法使用它。当客户端尝试从数据库读取时,我得到 Segmentation fault。我真的很想了解如何将本地文件读取到服务器并将其用作数据库,然后在客户端开始发出请求并因此将数据传递给客户端时使用该数据库。

任何帮助将不胜感激..

定义:

#define  SERVER_BUSY    0
#define  SERVER_READY   1
#define  DATA_CONSUMED  2
#define  REQUEST        3
#define  BUSY           4

#define  SEARCH 0
#define  GETALL 1
#define  INSERT 2

#define MAX 100

struct SharedMemory 
    int  requestType;
    int  processId;
    int  status;
    char names[1];
    int  fakNums[1];
    int  count;
;

这是我的服务器实现:

void  main(int  argc, char *argv[]) 
     key_t          sharedMemoryKey;
     int            sharedMemoryId;
     struct SharedMemory  *sharedMemoryPointer;

     sharedMemoryKey = ftok(".", 'x'); 
     sharedMemoryId = shmget(sharedMemoryKey, sizeof(struct SharedMemory), IPC_CREAT | 0666);
     if (sharedMemoryId < 0) 
          printf("SERVER ERROR\n");
          exit(1);
     

     sharedMemoryPointer = (struct SharedMemory *) shmat(sharedMemoryId, NULL, 0);
     if ((int) sharedMemoryPointer == -1) 
          printf("SHARED MEMERY ERROR\n");
          exit(1);
     

     printf("ATTACHED TO SHARED MEMORY...\n");

     printf("START CLIENT...\n");
    //temp data
    int totalCount = 1;
    struct SharedMemory sharedMem;
    for (int i = 0; i < totalCount; i++) 
        sharedMem.names[i] = "NAME";
        sharedMem.fakNums[i] = i;
    
    //-temp data  

     sharedMemoryPointer->status = SERVER_READY;
     while (1) 
    if  (sharedMemoryPointer->status != REQUEST) 
            sleep(1);
     else 
        printf("START WORKING...\n");
        sharedMemoryPointer->status = SERVER_BUSY;
        int requestType = sharedMemoryPointer->requestType;
        switch (requestType) 
            case SEARCH : 
                int pos = 0;
                for (int i = 0; i < totalCount; i++) 
                    if (strcmp(sharedMem.names[i], sharedMemoryPointer->names[0]) == 0)
                        strcpy(sharedMemoryPointer->names[pos], sharedMem.names[i]);
                        sharedMemoryPointer->fakNums[pos] =  sharedMem.fakNums[i];
                        pos++;
                        break;
                    
                
                sharedMemoryPointer->count = pos;
                break;
                
            case GETALL : 
                for (int i = 0; i < totalCount; i++) 
                    strcpy(sharedMemoryPointer->names[i], sharedMem.names[i]);
                    sharedMemoryPointer->fakNums[i] =  sharedMem.fakNums[i];
                
                sharedMemoryPointer->count = totalCount;
                break;
                
            case INSERT : 
                strcpy(sharedMem.names[totalCount], sharedMemoryPointer->names[0]);
                sharedMem.fakNums[totalCount] = sharedMemoryPointer->fakNums[0];
                totalCount; 
                break;
                

         

        int clientPid = sharedMemoryPointer->processId;
        printf("WAKE UP THE PROCESS...\n");
        kill(clientPid, SIGCONT);

        sharedMemoryPointer->status = SERVER_READY;
    
     

这是我的客户端实现:

void onServerReady();

key_t          sharedMemoryKey;
int            sharedMemoryId;
struct SharedMemory  *sharedMemoryPointer;

bool isSearching = false;
bool isInserting = false;
bool isFetchingAll = false;

void  main(int  argc, char *argv[]) 

     //init

     char* SEARCHARG =  "-s";
     char* INSERTARG =  "-i";
     char* LISTARG   =  "-l";

     sharedMemoryKey = ftok(".", 'x');
     sharedMemoryId = shmget(sharedMemoryKey, sizeof(struct SharedMemory), 0666);
     if (sharedMemoryId < 0) 
          printf("SHARED MEMORY ERROR\n");
          exit(1);
     

     sharedMemoryPointer = (struct SharedMemory *) shmat(sharedMemoryId, NULL, 0);
     if ((int) sharedMemoryPointer == -1) 
          printf("*** shmat error (client) ***\n");
          exit(1);
     
     printf("   CLIENT ATTACHED TO SHARED MEMORY\n");

     signal(SIGCONT, onServerReady);

     //set our request
     if (argc < 2) 
        printf("  NO ARGS. EXITING\n");
    exit(1);
     

     if (strcmp(argv[1], SEARCHARG) == 0) 
    isSearching = true;
    if (argc < 3) 
            printf("  NOT ENOUGH ARGS. EXITING\n");
        exit(1);
        
    while (sharedMemoryPointer->status != SERVER_READY) 
        sleep(1);
     
    sharedMemoryPointer->status = BUSY;
    sharedMemoryPointer->processId = getpid();
    sharedMemoryPointer->requestType = SEARCH;
    strcpy(sharedMemoryPointer->names[0], argv[2]);
    sharedMemoryPointer->status = REQUEST;
      else if (strcmp(argv[1], LISTARG) == 0) 
    isFetchingAll = true;
    while (sharedMemoryPointer->status != SERVER_READY) 
        sleep(1);
    
    sharedMemoryPointer->status = BUSY;
    sharedMemoryPointer->processId = getpid();
    sharedMemoryPointer->requestType = GETALL;
    sharedMemoryPointer->status = REQUEST;
      else if (strcmp(argv[1], INSERTARG) == 0) 
    isInserting = true;
    if (argc < 4) 
            printf("  NOT ENOUGH ARGS. EXITING\n");
        exit(1);
        
    while (sharedMemoryPointer->status != SERVER_READY) 
        sleep(1);
     
    sharedMemoryPointer->status = BUSY;
    sharedMemoryPointer->processId = getpid();
    sharedMemoryPointer->requestType = INSERT;
    strcpy(sharedMemoryPointer->names[0], argv[2]);
    sharedMemoryPointer->fakNums[0] = atoi(argv[3]);
    sharedMemoryPointer->status = REQUEST;
     

     //wait
     pause();

     //while (sharedMemoryPointer->status != FILLED)
     //     ;
    // printf("   Client found the data is ready...\n");
     //printf("   Client found %d %d %d %d in shared memory...\n",
         //       sharedMemoryPointer->data[0], sharedMemoryPointer->data[1], 
       //         sharedMemoryPointer->data[2], sharedMemoryPointer->data[3]);

    // sharedMemoryPointer->status = TAKEN;
    // printf("   Client has informed server data have been taken...\n");
    // shmdt((void *) sharedMemoryPointer);
   //  printf("   Client has detached its shared memory...\n");
    // printf("   Client exits...\n");
    // exit(0);


void onServerReady() 
    if (isFetchingAll || isSearching) 
        int count = sharedMemoryPointer->count;
printf("\n %d", count);
        //for (int i = 0; i < count; i++) 
        //  printf("Name %s, fakNum %d \n", sharedMemoryPointer->names[i], sharedMemoryPointer->fakNums[i]);            
        //
     else 
        printf("\nSuccessfull insertion!");
    

【问题讨论】:

除了 gpeche 在他的有用答案中解决的问题之外,这对于 sysv shm 来说听起来并不是一件好事。您应该使用面向消息的东西,系统 v 消息队列,或者甚至更好的 unix 域套接字、udp 等 【参考方案1】:

我的 C 有点生疏了,但看起来你的 SharedMemory 结构(位于 SysV 共享内存中)正在加载指向非共享内存中的 Data 的指针(通过 malloc 分配,或者静态地在进程的私有内存空间内)这在另一边是行不通的,因为:

指向的内存仍然是私有的,不共享。 即使它是共享的,它的内存地址在每个进程的内存映射中也可能不同(也就是说,共享内存块可能位于服务器中的 addr=1000 和客户端中的 addr=2000 ; 在一侧写“1000”将指向另一侧的错误位置)

您应该使用shmget 分配一个足够大的内存块以容纳您想要共享的所有内容,然后将所有信息放入该块中。避免使用指针,将信息嵌入到您的共享内存结构中。

【讨论】:

感谢您的帮助!但是,当我尝试将信息嵌入到我的结构 SharedMemory char names[20] 中时,shmget() 方法不起作用。你知道为什么会这样吗? 我已经更新了我的代码。你能指导我如何制作学生信息数组(姓名和数字作为字符串)并从文件中加载它们吗? @Calihog 您应该将您的结构定义添加到问题中,如果不知道这些,很难知道发生了什么。 是的,抱歉。我已经在上面的帖子中添加了定义!

以上是关于具有共享内存和文件作为数据库的 IPC V 客户端/服务器应用程序,用 C 编写的主要内容,如果未能解决你的问题,请参考以下文章

RE:Posix 和 System V IPC

五十进程间通信——System V IPC 之共享内存

System V IPC 之共享内存

进程间通信---mmap详解(与system V ipc通信对照)

Linux编程入门一System V共享内存

System V IPC相关函数