LINUX C POSIX共享内存实现

这个示例展示了如何在C语言中使用共享内存进行进程间的通信。`shm.h`包含了相关定义和宏,`shm.c`实现了读写函数,`testshmserver.c`创建并填充共享内存,`testshmclient.c`从共享内存读取数据。代码通过`shm_open`, `mmap`, `ftruncate`等系统调用来创建和操作共享内存,并提供了读写和同步的函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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操作。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值