一、 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,.$@.d -c $< -o $@clean:rm -rf .*.o.d *.o $(OJB_OUT)
二、 工程模板(消息队列和共享内存)
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 32struct shm_param
{int id; //共享内存IDsize_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);}//创建keykey = 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);}//创建keykey = 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);}//创建keykey = 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);//创建keykey = 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,.$@.d -c $< -o $@clean:rm -rf .*.o.d *.o $(OJB_OUT)
三、工程模板中通信组件的使用
以下组件依赖临时目录,必须提前创建(tmp目录是内存型目录,如果重启了系统会消失,所以每次重启后注意重新创建下)
mkdir /tmp/ipc/shmem -p
mkdir /tmp/ipc/msgqueue/peer -p
1. 消息队列
源码阅读:
(1)发送程序:
#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)接收程序:
#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)写入共享内存
#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(¶, "shm_test", 1024);if(ret < 0){return -1;}struct student *addr = shm_getaddr(¶);if(addr == NULL){return -1;}addr->num = 10;strcpy(addr->name, "zhangsan");return 0;
}
(2)读取共享内存
#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(¶, "shm_test", 1024);if(ret < 0){return -1;}struct student *addr = shm_getaddr(¶);if(addr == NULL){return -1;}printf("num = %d\n", addr->num);printf("num = %s\n", addr->name);shm_del(¶);return 0;
}
3. 共享内存中读写结构体数组的使用
假设学生信息结构体定义如下:
struct student
{int num;char name[16];
}
定义a、b两个进程,a进程创建若干个(个数自己决定,是可变的)学生,填充任意的信息,通过共享内存将学生信息共享给b进程(包括学生个数)。b进程拿到信息后打印到终端。
提示:这里可巧妙的利用指针的操作,先申请足够大的共享内存,映射后然后通过不同类型的指针来操作和读取内容中的数据。模型图如下:
(1)共享内存写入结构体数组和大小
#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(¶, "shm_test", MAX_NODE_SIZE);if(ret < 0){return -1;}void *node_p = shm_getaddr(¶);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)共享内存读取结构体数组
#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(¶, "shm_test", MAX_NODE_SIZE);if(ret < 0){return -1;}void *node_p = shm_getaddr(¶);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(¶);return 0;
}