1.为了演示方便,由两个不同的进程对共享内存进行操作,一个进程为服务端(提供数据源),另一个客户端(读取数据)
shm.h
#ifndef _SHM_H_
#define _SHM_H_
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <iconv.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/stat.h> /* For mode constants */
#include <mqueue.h>
#include <sys/mman.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/select.h>
#include <sys/epoll.h>
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#include <fcntl.h> /* For O_* constants */
#endif
#ifndef _BSD_SOURCE
#define _BSD_SOURCE
#include <unistd.h>
#include <sys/types.h>
#endif
#define PRINT_SYSERR(FORMAT,MSGS...) printf(FORMAT" SYS RETCODE MEANS:[%s]\n",##MSGS,strerror(errno));
#define PRINTLN(FORMAT,MSGS...) printf(FORMAT"\n",##MSGS);
typedef struct _shm_handle_
{
int shmfd;
char shmname[200];
void *shmaddr;
size_t shmsize;
void *syncaddr;
size_t syncsize;
int syncflag;
struct _shm_handle_ *next;
}Shmhandle_t;
#endif
shm.c
#include "shm.h"
ssize_t Readn(int fd,void *buff,size_t size)
{
size_t offset = 0, leftsize = 0;
ssize_t nbytes = 0;
void *ptr = buff;
leftsize = size;
while(leftsize > 0){
nbytes = read(fd,ptr+offset,leftsize);
if(nbytes <= 0){
if(errno == EINTR)
continue;
else if(errno == EAGAIN)
break;
else
return -1;
}
leftsize -= nbytes;
offset += nbytes;
}
return nbytes - leftsize;
}
ssize_t Writen(int fd,const void *buff,size_t size)
{
size_t offset = 0, leftsize = 0;
ssize_t nbytes = 0;
const void *ptr = buff;
leftsize = size;
while(leftsize > 0){
nbytes = write(fd,ptr+offset,leftsize);
if(nbytes <= 0){
switch (errno)
{
case EINTR:
continue;
case EAGAIN:
usleep(100);
continue;
default:
return -1;
}
}
leftsize -= nbytes;
offset += nbytes;
}
return nbytes - leftsize;
}
/***
* flag:O_CREAT O_RDWR O_TRUNC O_RDONLY O_EXCL (not include O_APPEND)
* perm: you can use 0666 0777 0755 like function-open
* ***/
Shmhandle_t* OpenShm_P(const char *name,size_t msize,int flag,unsigned int perm)
{
int shmfd = 0;
void *addr = NULL;
shmfd = shm_open(name,flag,perm);
if(shmfd < 0){
goto error;
}
if(msize < 4096)
msize = 4096;
ftruncate(shmfd,msize);
addr = mmap(NULL,msize,PROT_READ|PROT_WRITE,MAP_SHARED,shmfd,0);
if(addr == NULL)
goto error;
Shmhandle_t *handle = (Shmhandle_t *)malloc(sizeof(Shmhandle_t));
if(handle == NULL)
goto error;
memmove(handle->shmname,name,strlen(name));
handle->shmsize = msize;
handle->shmfd = shmfd;
handle->shmaddr = addr;
handle->next = NULL;
return handle;
error:
if(shmfd > 2)
close(shmfd);
if(addr != NULL)
munmap(addr,msize);
shm_unlink(name);
return NULL;
}
ssize_t ReadnShm_P(Shmhandle_t *handle,void *buff,size_t size)
{
return Readn(handle->shmfd,buff,size);
}
ssize_t WritenShm_P(Shmhandle_t *handle,const void *buff,size_t size)
{
return Writen(handle->shmfd,buff,size);
}
int SyncShm_P(Shmhandle_t *handle)
{
if(handle == NULL)
return -1;
return msync(handle->syncaddr,handle->syncsize,handle->syncsize);
}
/***
* only free handle and munmap,do not unlink shm
* ***/
int CloseShm_P(Shmhandle_t** shandle)
{
Shmhandle_t *handle = *shandle;
if(handle == NULL)
return 0;
munmap(handle->shmaddr,handle->shmsize);
close(handle->shmfd);
// shm_unlink(handle->shmname);
free(handle);
handle = NULL;
*shandle = handle;
return 0;
}
int UnlinkShm_P(const char *name)
{
shm_unlink(name);
return 0;
}
testshmserver.c
#include "shm.h"
typedef struct _wuser_entry_
{
char user_id[30];
char user_password[129];
char user_name[100];
}WuserEntry;
typedef struct _wuser_
{
WuserEntry *entry;
size_t size;
}Wuser_t;
Wuser_t* CreateWuser(size_t size)
{
Wuser_t *user = (Wuser_t *)malloc(sizeof(Wuser_t));
if(user == NULL)
goto error;
bzero(user,sizeof(Wuser_t));
user->entry = (WuserEntry *)malloc(sizeof(WuserEntry)*size);
if(user->entry == NULL)
goto error;
bzero(user->entry,sizeof(WuserEntry)*size);
user->size = size;
return user;
error:
if(user != NULL){
if(user->entry != NULL)
free(user->entry);
free(user);
}
return NULL;
}
int MakeWuserTestData(Wuser_t *user)
{
if(user == NULL || user->entry == NULL)
return -1;
int ii = 0;
for(ii = 0; ii < user->size; ii++){
snprintf(user->entry[ii].user_id,sizeof(user->entry[ii].user_id),"testid%02d",ii);
snprintf(user->entry[ii].user_name,sizeof(user->entry[ii].user_name),"testname%02d",ii);
snprintf(user->entry[ii].user_password,sizeof(user->entry[ii].user_password),"testpswd%02d",ii);
}
return 0;
}
int CloseWuser(Wuser_t **user)
{
Wuser_t *puser = *user;
if(puser != NULL){
if(puser->entry != NULL)
free(puser->entry);
free(puser);
}
*user = NULL;
return 0;
}
int main()
{
Shmhandle_t *shandle = NULL;
Wuser_t *user = NULL;
int ret = 0;
user = CreateWuser(1000);
if(user == NULL)
goto error;
ret = MakeWuserTestData(user);
if(ret < 0)
goto error;
shandle = OpenShm_P("shmtest",(user->size)*sizeof(WuserEntry),O_CREAT|O_RDWR,0664);
if(shandle == NULL)
goto error;
WritenShm_P(shandle,(void *)user->entry, (user->size)*sizeof(WuserEntry));
// 直接往内存拷贝也可以。
//memcpy(shandle->shmaddr,user->entry,(user->size)*sizeof(WuserEntry));
CloseWuser(&user);
CloseShm_P(&shandle);
return 0;
error:
PRINT_SYSERR();
CloseWuser(&user);
CloseShm_P(&shandle);
//UnlinkShm_P(&shandle); if you do not want drop this share memory from /dev/shm, be carefully use unlink
return -1;
}
testshmclient.c
#include "shm.h"
typedef struct _wuser_entry_
{
char user_id[30];
char user_password[129];
char user_name[100];
}WuserEntry;
typedef struct _wuser_
{
WuserEntry *entry;
size_t size;
}Wuser_t;
Wuser_t* CreateWuser(size_t size)
{
Wuser_t *user = (Wuser_t *)malloc(sizeof(Wuser_t));
if(user == NULL)
goto error;
bzero(user,sizeof(Wuser_t));
user->entry = (WuserEntry *)malloc(sizeof(WuserEntry)*size);
if(user->entry == NULL)
goto error;
bzero(user->entry,sizeof(WuserEntry)*size);
user->size = size;
return user;
error:
if(user != NULL){
if(user->entry != NULL)
free(user->entry);
free(user);
}
return NULL;
}
int CloseWuser(Wuser_t **user)
{
Wuser_t *puser = *user;
if(puser != NULL){
if(puser->entry != NULL)
free(puser->entry);
free(puser);
}
*user = NULL;
return 0;
}
int PrintAllWuser(const Wuser_t *user)
{
if(user == NULL || user->entry == NULL)
return -1;
int ii = 0;
for(ii = 0; ii < user->size; ii++){
printf("id:[%s] name:[%s] pswd[%s]\n",user->entry[ii].user_id,user->entry[ii].user_name,user->entry[ii].user_password);
}
printf("Has print [%d] users\n",ii);
return 0;
}
int main()
{
Shmhandle_t *chandle = NULL;
Wuser_t *user = NULL;
user = CreateWuser(1000);
if(user == NULL)
goto error;
chandle = OpenShm_P("shmtest",(user->size)*sizeof(WuserEntry),O_RDWR,0664);
if(chandle == NULL)
goto error;
ReadnShm_P(chandle,user->entry,(user->size)*sizeof(WuserEntry));
// 直接往内存拷贝也可以。
//memcpy(user->entry,chandle->shmaddr,(user->size)*sizeof(WuserEntry));
PrintAllWuser(user);
CloseWuser(&user);
CloseShm_P(&chandle);
return 0;
error:
PRINT_SYSERR();
CloseWuser(&user);
CloseShm_P(&chandle);
//UnlinkShm_P(&chandle); if you do not want drop this share memory from /dev/shm, be carefully use unlink
return -1;
}
gcc testshmserver.c shm.c -oserver -lrt
gcc testshmclient.c shm.c -oclient -lrt
其实往共享内存读/写数据时,只要不关闭文件描述符,可以拿来read write操作。