一、 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 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,.$@.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;
}