Makefile模板和工程模板(消息队列和共享内存)的使用

一、 Makefile模板

cpp 复制代码
#指定生成的文件名
OJB_OUT = test

#指定每一个c文件对应的.o文件
OBJS = a.o b.o main.o

#指定编译器
CC = gcc

#指定需要的库
ULDFLAGS = 

###########################################
#以下的内容不需要修改
###########################################
all:$(OJB_OUT)

$(OJB_OUT):$(OBJS)
	$(CC) -o $@ $^ $(ULDFLAGS)

dep_files := $(foreach f,$(OBJS),.$(f).d)
dep_files := $(wildcard $(dep_files))

ifneq ($(dep_files),)
  include $(dep_files)
endif

$(OBJS):%.o:%.c
	$(CC) -Wp,-MD,.$@.d -c $< -o $@
    
clean:
	rm -rf .*.o.d *.o $(OJB_OUT)

二、 工程模板(消息队列和共享内存)

1. pub_define.h

cpp 复制代码
/***********************************************************************************
Description:    类型重定义
***********************************************************************************/
#ifndef __PUB_DEFINE_H
#define __PUB_DEFINE_H

#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>

#define MAX_PROC_NAME_SZ    32

#define MAX_PATH_LEN 256  //最大路径长度

#ifdef BOOL
#undef BOOL
#endif

#ifdef FALSE
#undef FALSE
#endif

#ifdef TRUE
#undef TRUE
#endif

#define BOOL    int
#define FALSE   (0)
#define TRUE    (!FALSE)

#define KB 1024
#define MB (1024*KB)
#define GB (1024*MB)

#define UNUSED(x) (void)x;  //仅仅为了消除警告用,可解决未定义变量

#include <stdint.h>

#define uint8  uint8_t
#define uint16 uint16_t
#define uint32 uint32_t

#define int8  int8_t
#define int16 int16_t
#define int32 int32_t

#define SLEEP_MS(ms) usleep(ms*1000)

#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))

#endif //__PUB_DEFINE_H

2. msg_queue_peer.h

cpp 复制代码
/***********************************************************************************
Description:    点对点型消息队列组件
***********************************************************************************/

#ifndef MSG_QUEUE_PEER_H
#define MSG_QUEUE_PEER_H

#include "pub_define.h"
#include <sys/ipc.h>
#include <sys/msg.h>

int msg_queue_send(const char *name, const void *msg, size_t msgsz, int msgflg);
int msg_queue_recv(const char *name, void *msg, size_t msgsz, long msgtyp, int msgflg);

#endif  // MSG_QUEUE_PEER_H

3. shmem.h

cpp 复制代码
/***********************************************************************************
Description:    提供共享内存组件
***********************************************************************************/

#ifndef SHMEM_H
#define SHMEM_H

#include "pub_define.h"
#include <sys/ipc.h>
#include <sys/shm.h>

#define SHM_NAME_SZ    32

struct shm_param
{
    int id;                       //共享内存ID
    size_t size;
    void *addr;                   //共享内存地址
    char name[SHM_NAME_SZ+1];     //共享内存key标识
};

int shm_init(struct shm_param *para, const char *name, size_t size);
void *shm_getaddr(struct shm_param *para);
void shm_write(const struct shm_param *para, void *data, size_t size);
int shm_del(const struct shm_param *para);

#endif  // SHMEM_H

4. msg_queue_peer.c

cpp 复制代码
/***********************************************************************************
Description:    点对点型消息队列组件
***********************************************************************************/

#include <errno.h>
#include "msg_queue_peer.h"

#define MSG_PATH "/tmp/ipc/msgqueue/peer/"

#define MAGIC_ID 'j'

/**
 * @brief msg_queue_send
 * @param name 发送给哪个消息队列
 * @param msg 消息数据,第一个字段必须是long类型的消息类型
 * @param msgsz 整个msg大小,不需要减去long--sizeof(*msg)
 * @param msgflg 同msgsnd
 * @return 同msgsnd
 */
int msg_queue_send(const char *name, const void *msg, size_t msgsz, int msgflg)
{
    assert(NULL != name && strlen(name) > 0);
    assert(NULL != msg);

    key_t key;
    int ret;
    int msgid;
    char sys_cmd[256];
    char path[256];

    sprintf(path, "%s%s", MSG_PATH, name);

    //文件不存在创建
    if(access(path, F_OK) < 0)
    {
        sprintf(sys_cmd, "%s %s", "touch", path);
        ret = system(sys_cmd);
        UNUSED(ret);
    }

    //创建key
    key = ftok(path, MAGIC_ID);
    if(key < 0){
        perror("fail to ftok");
        return -1;
    }

    //创建消息队列
    msgid = msgget(key, IPC_CREAT|0666);
    if (msgid < 0)
    {
        perror("fail to msgget");
        return -1;
    }

    return msgsnd(msgid, msg, msgsz - sizeof(long), msgflg);
}

/**
 * @brief msg_queue_send
 * @param name 从哪个消息队列接收
 * @param msg 消息缓冲区,第一个字段必须是long类型的消息类型
 * @param msgsz 整个msg大小,不需要减去long--sizeof(*msg)
 * @param msgtyp 同msgrcv
 * @param msgflg 同msgrcv
 * @return 同msgrcv
 */
int msg_queue_recv(const char *name, void *msg, size_t msgsz, long msgtyp, int msgflg)
{
    assert(NULL != name && strlen(name) > 0);
    assert(NULL != msg);

    key_t key;
    int ret;
    int msgid;
    char sys_cmd[256];
    char path[256];

    sprintf(path, "%s%s", MSG_PATH, name);
    //文件不存在创建
    if(access(path, F_OK) < 0)
    {
        sprintf(sys_cmd, "%s %s", "touch", path);
        ret = system(sys_cmd);
        UNUSED(ret);
    }

    //创建key
    key = ftok(path, MAGIC_ID);
    if(key < 0){
        perror("fail to ftok");
        return -1;
    }

    //创建消息队列
    msgid = msgget(key, IPC_CREAT|0666);
    if (msgid < 0)
    {
        perror("fail to msgget");
        return -1;
    }

    return msgrcv(msgid, msg, msgsz - sizeof(long), msgtyp, msgflg);
}


/**
 * @brief 判断某个类型的消息是否存在,但是不取出
 * @param name 指定消息队列名
 * @param msgtyp 消息类型
 * @return TRUE FALSE
 */
BOOL msg_queue_msgexist(const char *name, long msgtyp)
{
    assert(NULL != name && strlen(name) > 0);

    key_t key;
    int ret;
    int msgid;
    char sys_cmd[256];
    char path[256];

    sprintf(path, "%s%s", MSG_PATH, name);
    //文件不存在创建
    if(access(path, F_OK) < 0)
    {
        sprintf(sys_cmd, "%s %s", "touch", path);
        ret = system(sys_cmd);
        UNUSED(ret);
    }

    //创建key
    key = ftok(path, MAGIC_ID);
    if(key < 0)
    {
        perror("fail to ftok");
        return -1;
    }

    //创建消息队列
    msgid = msgget(key, IPC_CREAT|0666);
    if (msgid < 0)
    {
        perror("fail to msgget");
        return -1;
    }

    if(msgrcv(msgid, NULL, 0, msgtyp, IPC_NOWAIT) < 0)
    {
        if(errno == E2BIG)
        {
            return TRUE;
        }
    }
    return FALSE;
}

5. shmem.c

cpp 复制代码
/***********************************************************************************
Description:    提供共享内存组件
***********************************************************************************/

#include "shmem.h"

#define MAGIC_ID 'j'

/**
 * @brief 初始化共享内存
 * @param para 参数结构体,传入即可
 * @param name 共享内存标识名称
 * @return 0 -1
 */
int shm_init(struct shm_param *para, const char *name, size_t size)
{
    assert(NULL != para);
    assert(NULL != name && strlen(name) > 0);
    key_t key;
    int ret;
    int id;
    char sys_cmd[256];
    char path[256];

    sprintf(path, "/tmp/ipc/shmem/%s", name);
    sprintf(sys_cmd, "%s %s", "touch", path);
    ret = system(sys_cmd);
    UNUSED(ret);

    //创建key
    key = ftok(path, MAGIC_ID);
    if(key < 0){
        perror("fail to ftok");
        printf("error :path = %s\n", path);
        return -1;
    }

    //创建共享内存
    id = shmget(key, size, IPC_CREAT|0666);
    if (id < 0)
    {
        perror("fail to shmget");
        return -1;
    }

    para->id = id;
    para->size = size;
    strcpy(para->name, name);

    return 0;
}

/**
 * @brief 获取共享内存地址
 * @param para
 * @return 失败返回NULL
 */
void *shm_getaddr(struct shm_param *para)
{
    void *addr;
    addr = shmat(para->id, NULL, 0);
    if(addr == (void *)-1)
    {
        para->addr = NULL;
    }
    else
    {
        para->addr = addr;
    }

    return para->addr;
}

/**
 * @brief 写共享内存
 * @param para
 * @param data
 * @param size
 */
void shm_write(const struct shm_param *para, void *data, size_t size)
{
    assert(size <= para->size);
    assert(NULL != data);

    memcpy(para->addr, data, size);
}

/**
 * @brief 解除共享内存
 * @param para
 * @return
 */
int shm_del(const struct shm_param *para)
{
    assert(NULL != para);
    int ret = shmdt(para->addr);
    if(ret < 0)
    {
        perror("fail to shmdt");
        return -1;
    }

    ret = shmctl(para->id, IPC_RMID, NULL);
    if(ret < 0)
    {
        perror("fail to shmctl");
        return -1;
    }

    return 0;
}

6. main.c

cpp 复制代码
#include <stdio.h>

int main(int argc, char *argv[])
{
    printf("project demo\n");

    return 0;
}

7. Makefile

cpp 复制代码
#指定生成的文件名
OJB_OUT = test


#指定每一个c文件对应的.o文件
OBJS = shmem.o msg_queue_peer.o main.o


#指定编译器
CC = gcc


#指定需要的库和路径
ULDFLAGS = 


###########################################
#以下的内容不需要修改
###########################################
all:$(OJB_OUT)


$(OJB_OUT):$(OBJS)
	$(CC) -o $@ $^ $(ULDFLAGS)


dep_files := $(foreach f,$(OBJS),.$(f).d)
dep_files := $(wildcard $(dep_files))


ifneq ($(dep_files),)
  include $(dep_files)
endif


$(OBJS):%.o:%.c
	$(CC) -Wp,-MD,.$@.d -c $< -o $@
    
clean:
	rm -rf .*.o.d *.o $(OJB_OUT)

三、工程模板中通信组件的使用

以下组件依赖临时目录,必须提前创建(tmp目录是内存型目录,如果重启了系统会消失,所以每次重启后注意重新创建下)

cpp 复制代码
mkdir /tmp/ipc/shmem -p
mkdir /tmp/ipc/msgqueue/peer -p

1. 消息队列

源码阅读:

(1)发送程序:

cpp 复制代码
#include "msg_queue_peer.h"

struct msgbuf
{
    long mtype;
    char mdata[256];
};

int main(int argc, char *argv[])
{
    struct msgbuf send_buf;

    //这个mtype可以不用,但是必须赋一个不小于0的数
    send_buf.mtype = 1;

    while (1)
    {
        gets(send_buf.mdata, 256);

        if(msg_queue_send("topic", &send_buf, sizeof(send_buf), 0) < 0)
        {
            printf("msg_queue_send error\n");
            return -1;
        }
    }

    return 0;
}

(2)接收程序:

cpp 复制代码
#include "msg_queue_peer.h"

struct msgbuf
{
    long mtype;
    char mdata[256];
};

int main(int argc, char *argv[])
{
    struct msgbuf recv_buf;

    while (1)
    {
        if(msg_queue_recv("topic", &recv_buf, sizeof(recv_buf), 0, 0) > 0)
        {
            printf("recv from msga type = %ld\n", recv_buf.mtype);
            printf("recv from msga data = %s\n", recv_buf.mdata);
        }
        else
        {
            perror("recv error:");
            return -1;
        }
    }

    return 0;
}

2. 共享内存

(1)写入共享内存

cpp 复制代码
#include "shmem.h"

static struct shm_param para;

struct student
{
    int num;
    char name[64];
};

int main(int argc, char *argv[])
{
    int ret = -1;

    ret = shm_init(&para, "shm_test", 1024);
    if(ret < 0)
    {
        return -1;
    }

    struct student *addr = shm_getaddr(&para);
    if(addr == NULL)
    {
        return -1;
    }

    addr->num = 10;
    strcpy(addr->name, "zhangsan");

    return 0;
}

(2)读取共享内存

cpp 复制代码
#include "shmem.h"

static struct shm_param para;

struct student
{
    int num;
    char name[64];
};

int main(int argc, char *argv[])
{
    int ret = -1;

    ret = shm_init(&para, "shm_test", 1024);
    if(ret < 0)
    {
        return -1;
    }

    struct student *addr = shm_getaddr(&para);
    if(addr == NULL)
    {
        return -1;
    }

    printf("num = %d\n", addr->num);
    printf("num = %s\n", addr->name);

    shm_del(&para);

    return 0;
}

3. 共享内存中读写结构体数组的使用

假设学生信息结构体定义如下:

cpp 复制代码
struct student
{
    int num;
    char name[16];
}

定义a、b两个进程,a进程创建若干个(个数自己决定,是可变的)学生,填充任意的信息,通过共享内存将学生信息共享给b进程(包括学生个数)。b进程拿到信息后打印到终端。

提示:这里可巧妙的利用指针的操作,先申请足够大的共享内存,映射后然后通过不同类型的指针来操作和读取内容中的数据。模型图如下:

(1)共享内存写入结构体数组和大小

cpp 复制代码
#include "shmem.h"

static struct shm_param para;

struct student
{
    int num;
    char name[64];
};

static int *total;  //指向共享内存中数据节点总个数
static struct student *node_arr;  //指向共享内存中节点缓存数组头

#define MAX_NODE 128  //最大支持学生数目
#define STD_NODE_LEN sizeof(struct student)
#define MAX_NODE_SIZE (MAX_NODE * STD_NODE_LEN)

int main(int argc, char *argv[])
{
    int ret = -1;

    ret = shm_init(&para, "shm_test", MAX_NODE_SIZE);
    if(ret < 0)
    {
        return -1;
    }

    void *node_p = shm_getaddr(&para);
    if(node_p == NULL)
    {
        return -1;
    }

    memset(node_p, 0, MAX_NODE_SIZE);

    //前4个字节存储实际的学生数目
    total = (int *)node_p;
    //后面空间存储数据点
    node_arr = (struct student *)(node_p + sizeof(int));

    *total = 3;  //假设有3个人

    //第1个人赋值
    node_arr[0].num = 1;
    strcpy(node_arr[0].name, "zhangsan");

    //第2个人赋值
    node_arr[1].num = 2;
    strcpy(node_arr[1].name, "lisi");

    //第3个人赋值
    node_arr[2].num = 3;
    strcpy(node_arr[2].name, "wangwu");

    return 0;
}

(2)共享内存读取结构体数组

cpp 复制代码
#include "shmem.h"

static struct shm_param para;

struct student
{
    int num;
    char name[64];
};

static int *total;  //指向共享内存中数据节点总个数
static struct student *node_arr;  //指向共享内存中节点缓存数组头

#define MAX_NODE 128  //最大支持学生数目
#define STD_NODE_LEN sizeof(struct student)
#define MAX_NODE_SIZE (MAX_NODE * STD_NODE_LEN)

int main(int argc, char *argv[])
{
    int ret = -1;

    ret = shm_init(&para, "shm_test", MAX_NODE_SIZE);
    if(ret < 0)
    {
        return -1;
    }


    void *node_p = shm_getaddr(&para);
    if(node_p == NULL)
    {
        return -1;
    }

    //前4个字节存储实际的学生数目
    total = (int *)node_p;
    //后面空间存储数据点
    node_arr = (struct student *)(node_p + sizeof(int));

    printf("num = %d\n", *total);
    int i;
    for(i=0; i<*total; i++)
    {
        printf("num=%d, name=%s\n", \
               node_arr[i].num,\
               node_arr[i].name);
    }

    //这个接口只有在这块共享内存不用了才能删除,项目中如果一直使用,不要调用这个接口
    shm_del(&para);

    return 0;
}
相关推荐
ac.char4 分钟前
在 Ubuntu 上安装 Yarn 环境
linux·运维·服务器·ubuntu
敲上瘾4 分钟前
操作系统的理解
linux·运维·服务器·c++·大模型·操作系统·aigc
长弓聊编程23 分钟前
Linux系统使用valgrind分析C++程序内存资源使用情况
linux·c++
陌小呆^O^27 分钟前
Cmakelist.txt之win-c-udp-client
c语言·开发语言·udp
cherub.30 分钟前
深入解析信号量:定义与环形队列生产消费模型剖析
linux·c++
梅见十柒1 小时前
wsl2中kali linux下的docker使用教程(教程总结)
linux·经验分享·docker·云原生
Koi慢热1 小时前
路由基础(全)
linux·网络·网络协议·安全
传而习乎1 小时前
Linux:CentOS 7 解压 7zip 压缩的文件
linux·运维·centos
我们的五年1 小时前
【Linux课程学习】:进程程序替换,execl,execv,execlp,execvp,execve,execle,execvpe函数
linux·c++·学习
IT果果日记2 小时前
ubuntu 安装 conda
linux·ubuntu·conda