Utilisation des modèles Makefile et des modèles de projet (file d'attente de messages et mémoire partagée)

1. Modèle de Makefile

#指定生成的文件名
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,[email protected] -c $< -o $@
    
clean:
	rm -rf .*.o.d *.o $(OJB_OUT)

2. Modèle de projet (file d'attente de messages et mémoire partagée)

1. pub_define.h

/***********************************************************************************
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

/***********************************************************************************
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

/***********************************************************************************
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

/***********************************************************************************
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

/***********************************************************************************
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

#include <stdio.h>

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

    return 0;
}

7. Makefile

#指定生成的文件名
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,[email protected] -c $< -o $@
    
clean:
	rm -rf .*.o.d *.o $(OJB_OUT)

3. L'utilisation des composants de communication dans les modèles de projet

Les composants suivants dépendent du répertoire temporaire et doivent être créés au préalable (le répertoire tmp est un répertoire de type mémoire et disparaîtra si le système est redémarré, veillez donc à le recréer après chaque redémarrage)

mkdir /tmp/ipc/shmem -p
mkdir /tmp/ipc/msgqueue/peer -p

1. File d'attente des messages

Lecture du code source :

(1) Procédure d'envoi :

#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) Procédure de réception :

#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. Mémoire partagée

(1) Écrire dans la mémoire partagée

#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) Lire la mémoire partagée

#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. L'utilisation de tableaux de structure de lecture et d'écriture dans la mémoire partagée

  Supposons que la structure d'informations sur les étudiants soit définie comme suit :

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

Définissez deux processus a et b. Le processus a crée un certain nombre d'étudiants (le nombre est déterminé par lui-même et est variable), remplit toutes les informations et partage les informations sur les étudiants avec le processus b (y compris le nombre d'étudiants) via la mémoire partagée. Une fois que le processus b a obtenu les informations, il les imprime sur le terminal.

Conseils : L'opération des pointeurs peut être utilisée intelligemment ici, appliquez d'abord une mémoire partagée suffisamment grande, puis utilisez différents types de pointeurs pour exploiter et lire les données dans le contenu après le mappage. Le schéma du modèle est le suivant :

(1) Tableau et taille de la structure d'écriture de la mémoire partagée

#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) Tableau de structure de lecture de mémoire partagée

#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;
}

Je suppose que tu aimes

Origine blog.csdn.net/qq_52049228/article/details/131991121
conseillé
Classement