C中的基本共享内存程序

Posted

技术标签:

【中文标题】C中的基本共享内存程序【英文标题】:Basic shared memory program in C 【发布时间】:2010-05-11 11:49:15 【问题描述】:

我想使用共享内存在 C 语言中制作一个基本的聊天应用程序。我在 Linux 中工作。应用程序在于写客户端和服务器可以读取,如果服务器写入客户端可以读取消息。

我尝试这样做,但我无法实现客户端和服务器之间的通信。代码如下:

服务器.c

int
main(int argc, char **argv)

 char *msg;
 static char buf[SIZE];
 int n;

 msg = getmem();
 memset(msg, 0, SIZE);
 initmutex();

 while ( true )
 
  if( (n = read(0, buf, sizeof buf)) > 0 )
  
   enter();
   sprintf(msg, "%.*s", n, buf);
   printf("Servidor escribe: %s", msg);
   leave();
  else
   enter();
   if ( strcmp(buf, msg) )
   
    printf("Servidor lee: %s", msg);
    strcpy(buf, msg);
   
   leave();
   sleep(1);
  
 
 return 0;
 

客户端.c

int
main(int argc, char **argv)

 char *msg;
 static char buf[SIZE-1];
 int n;

 msg = getmem();
 initmutex();

 while(true)
 
  if ( (n = read(0, buf, sizeof buf)) > 0 )
  
   enter();
   sprintf(msg, "%.*s", n, buf);
   printf("Cliente escribe: %s", msg);
   leave();
  else
   enter();
   if ( strcmp(buf, msg) )
   
    printf("Cliente lee: %s", msg);
    strcpy(buf, msg);
   
   leave();
   sleep(1);
  
 
 printf("Cliente termina\n");
 return 0;
 

共享内存模块如下:

#include "common.h"

void
fatal(char *s)

 perror(s);
 exit(1);


char *
getmem(void)

 int fd;
 char *mem;

 if ( (fd = shm_open("/message", O_RDWR|O_CREAT, 0666)) == -1 )
  fatal("sh_open");
 ftruncate(fd, SIZE);
 if ( !(mem = mmap(NULL, SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) )
  fatal("mmap");
 close(fd);
 return mem;


static sem_t *sd;

void
initmutex(void)

 if ( !(sd = sem_open("/mutex", O_RDWR|O_CREAT, 0666, 1)) )
  fatal("sem_open");


void
enter(void)

 sem_wait(sd);


void
leave(void)

 sem_post(sd);

【问题讨论】:

请正确格式化您的代码(或将其上传到 privatepaste 等粘贴箱)。 请告诉我们当您尝试运行我们的代码时发生了什么。 【参考方案1】:

等到您可以正常工作时,您将重新发明管道。套接字是更好的解决方案,它还涵盖了服务器和客户端不在同一台机器上运行的更常见的场景。

【讨论】:

【参考方案2】:
/* client */
#include <stdio.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>

#define SIZEOFSHMSEG 50         /* Size of the shared mem segment    */

#include<stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include<fcntl.h>
#define PORT        6002

int main()
 char buffer[512];
     int rc, shmid, i,l,choice,n;
     void *shm_address;
     struct shmid_ds shmid_struct;
 char c,ch;
     char HOST[30];
 char hostname[100];
 int sd;
 struct sockaddr_in sin;
 struct sockaddr_in pin;
 struct hostent *hp;

 printf("enter the server's ip address:");
 scanf("%s",HOST);
 n=strlen(HOST);
 HOST[n]='\0';


 if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
                perror("socket");
                exit(1);
        

 /* fill in the socket structure with host information */
 memset(&pin, 0, sizeof(pin));
 pin.sin_family = AF_INET;
 pin.sin_addr.s_addr = inet_addr(HOST);
 pin.sin_port = htons(PORT);


 /* connect to PORT on HOST */
 if (connect(sd,(struct sockaddr *)  &pin, sizeof(pin)) == -1) 
  perror("connect");
  exit(1);
 

  /* shared memory setup */
     shmid = shmget(2222, SIZEOFSHMSEG, 0666 | IPC_CREAT | IPC_EXCL);
     if (shmid == -1)
       
         printf("main: shmget() failed\n");
         return -1;
       

     /* Attach the shared memory segment to the server process.       */
     shm_address = shmat(shmid, NULL, 0);
     if ( shm_address==NULL )
       
         printf("main: shmat() failed\n");
         return -1;
       
 fcntl(sd, F_SETFL, O_NONBLOCK); 
 buffer[0]='\0';
 strcpy((char *)shm_address,buffer); 
 for(;;)
  
  printf("----------------------------------------------------------\n");
  printf("1.read from shared mem\n2.write to shared area\n3.exit\n");
  printf("ur choice:");
  scanf("%d",&choice);

  n = read(sd, buffer, 512);
  buffer[n] = '\0';
  strcpy((char *) shm_address, buffer);   

   if(choice==1)
    strcpy(buffer,(char *)shm_address);
    printf("display:%s\n",buffer);
   

   if(choice==2)
    printf("enter the data:");

    scanf(" %[^\n]",buffer);
    n=strlen(buffer);
    buffer[n]='\0';
    strcpy((char *) shm_address, buffer);
    write(sd, buffer, strlen(buffer));
   

   if(choice==3)
                         printf("terminated\n");
    break;
   
  printf("----------------------------------------------------------\n");
 
 close(sd);
 rc = shmdt(shm_address);
     if (rc==-1)
       
         printf("main: shmdt() failed\n");
         return -1;
       
     rc = shmctl(shmid, IPC_RMID, &shmid_struct);
     if (rc==-1)
       
         printf("main: shmctl() failed\n");
         return -1;
       
 return 0;

【讨论】:

【参考方案3】:
/* server */
#include <stdio.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#define SIZEOFSHMSEG 50         /* Size of the shared mem segment    */

#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#include<fcntl.h>
#define PORT   6002

int main()
 char buffer[512];
     int rc, shmid, i,l,choice,n;
     void * shm_address;
     struct shmid_ds shmid_struct;
 char c;

 int   sd, sd_current, cc;
 int   addrlen;
 struct   sockaddr_in sin;
 struct   sockaddr_in pin;

 /* get an internet domain socket */
 if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
  perror("socket");
  exit(1);
 

 /* complete the socket structure */
 memset(&sin, 0, sizeof(sin));
 sin.sin_family = AF_INET;
 sin.sin_addr.s_addr = htonl(INADDR_ANY);
 sin.sin_port = htons(PORT);

 /* bind the socket to the port number */
 if (bind(sd, (struct sockaddr *) &sin, sizeof(sin)) == -1) 
  perror("bind");
  exit(1);
 

 /* show that we are willing to listen */
 if (listen(sd, 5) == -1) 
  perror("listen");
  exit(1);
 

printf("waiting for client....\n");

 addrlen = sizeof(pin); 
 if ((sd_current = accept(sd, (struct sockaddr *)  &pin, &addrlen)) == -1) 
  perror("accept");
  exit(1);
 
printf("connected..\n");

 /* shared memory setup */
     shmid = shmget(1111, SIZEOFSHMSEG, 0666 | IPC_CREAT | IPC_EXCL);
     if (shmid == -1)
       
         printf("main: shmget() failed\n");
         return -1;
       

     /* Attach the shared memory segment to the server process.       */
     shm_address = shmat(shmid, NULL, 0);
     if ( shm_address==NULL )
       
         printf("main: shmat() failed\n");
         return -1;
       
buffer[0]='\0';
strcpy((char *)shm_address,buffer);

fcntl(sd_current, F_SETFL, O_NONBLOCK); 
 for(;;)
  

  printf("----------------------------------------------------------\n");
  printf("1.read from shared mem\n2.write to shared area\n3.exit\n");
  printf("ur choice:");
  scanf("%d",&choice);

  n=read(sd_current, buffer, 512);
  buffer[n] = '\0';
  strcpy((char *) shm_address, buffer);

   if(choice==1)
    strcpy(buffer,(char *)shm_address);
    printf("display:%s\n",buffer);
   

   if(choice==2)
    printf("enter the data:");
    scanf(" %[^\n]",buffer);
    n=strlen(buffer);
    buffer[n]='\0';

    strcpy((char *) shm_address, buffer);
    write(sd_current, buffer, strlen(buffer));
   
   if(choice==3)
                         printf("terminated\n");
    break;
   
  printf("----------------------------------------------------------\n");
 
 close(sd_current);
 close(sd);
 rc = shmdt(shm_address);
     if (rc==-1)
       
         printf("main: shmdt() failed\n");
         return -1;
       
     rc = shmctl(shmid, IPC_RMID, &shmid_struct);
     if (rc==-1)
       
         printf("main: shmctl() failed\n");
         return -1;
       
 return 0;

【讨论】:

以上是关于C中的基本共享内存程序的主要内容,如果未能解决你的问题,请参考以下文章

是否可以在 Windows 中的 PHP 和 C 之间共享内存?

C内存共享进程通信范例

共享内存程序中的意外输出

如何在 C 中与 Linux 一起使用共享内存

如何在c中制作共享内存?

使用信号访问共享内存到子进程