目录
消息队列
创建消息队列
删除消息队列
发送消息和接收
消息队列
消息队列就是一个消息的列表,进程可以在消息队列中添加消息和的读取消息
消息队列具有FIFO的特性,具有无名管道与有名管道各自的优势,可以支持任意两个进程的进程间通讯
就可以理解为打电话时,双方专属的通道
创建消息队列
创建消息队列调用 msgget 函数。消息队列需要生成密钥,理解为创建独一的电话线
函数头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
函数原型
int msgget(key_t key, int msgflg);
函数功能
获取System V消息队列标识符
[得到消息队列标识符或创建一个消息队列对象并返回消息队列标识符]
函数参数
key:由ftok函数合成
msgflg:消息队列标志
[0:取消息队列标识符,若不存在则函数会报错]
IPC_CREAT 创建标志
(如果内核中不存在键值与key相等的消息队列,则新建一个消息队列;如果存在这样的消息队
列,返回此消息队列的标识符)
[IPC_CREAT|IPC_EXCL: 如果消息队列存在,则报错, errno设置为EEXIST]
权限控制标志
IPC_CREAT | 0666
函数返回值
成功:返回消息队列id
失败:返回-1,并设置errno
代码:
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define PATHNAME "."
#define PROJ_ID 106
int main()
{
key_t key = ftok(PATHNAME,PROJ_ID);
if(key==-1)
{
perror("ftok");
exit(EXIT_FAILURE);
}
int msgid = msgget(key,IPC_CREAT | 0664);
if(msgid == -1)
{
perror("msgget");
exit(EXIT_FAILURE);
}
printf("msgid=%d\n",msgid);
return 0;
}
删除消息队列
删除消息队列需要调用 msgctl 函数
函数原型
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
函数参数
msqid:消息队列 id
cmd:命令字
IPC_STAT:获取消息队列属性
IPC_SET:设置消息队列属性
IPC_RMID:删除消息队列,用此命名时,第三个参数为NULL
buf:消息队列属性结构体对象指针
int msgid = msgget(key,IPC_CREAT | 0664);
if(msgid == -1)
{
perror("msgget");
exit(EXIT_FAILURE);
}
printf("msgid=%d\n",msgid);
// 删除消息队列
int ret = msgctl(msgid,IPC_RMID,NULL);
if(ret == -1)
{
perror("msgctl");
exit(EXIT_FAILURE);
}
printf("delete msg successful.\n");
发送消息和接收
发送消息队列需要调用 msgsnd 函数
函数原型
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
msqid:消息队列ID
msgp:消息结构体指针
msgsz:消息内容的长度
msgflg:消息队列标志,默认可以填0,IPC_NOWAIT,可以设置非阻塞
// 发送消息
struct msgbuf msg;
struct msgbuf* p_msg=&msg;
p_msg->mtype=MSG_TYPE;
strcpy(p_msg->msgtext,"Hello,first msg.");
int ret = msgsnd(msgid,(const void*)p_msg,strlen(p_msg-
>msgtext)+1,0);
接收消息调用 msgrcv 函数
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
msqid:消息队列id
msgp:消息结构指针
msgsz:最大读取的字节数
msgtyp:消息类型
msgflg:消息队列标志,默认可以填0,IPC_NOWAIT,可以设置非阻塞
//接收消息
struct msgbuf msg;
struct msgbuf* p_msg=&msg;
ssize_t rbytes = msgrcv(msgid,(void*)p_msg,MSG_SZ,MSG_TYPE,0);
共享内存
什么是共享内存
共享内存是将分配的物理空间直接映射到进程的用户虚拟地址空间中,减少数据在内核空间缓存
共享内存是一种效率较高的进程间通讯的方式
在 Linux 系统中通过 ipcs -m 查看所有的共享内存
创建共享内存
创建共享内存调用 shmget() 函数
函数原型
int shmget(key_t key, size_t size, int shmflg);
函数功能
创建一个共享内存,并返回ID
函数参数
key:由 ftok() 函数返回
size:共享内存的大小
shmflg:共享内存标志
#define PATH_NAME "."
#define PROJ_ID 110
#define SHM_SZ 1024
int main()
{
key_t key = ftok(PATH_NAME,PROJ_ID);
if(key == -1)
{
perror("ftok");
exit(EXIT_FAILURE);
}
int shmid = shmget(key,SHM_SZ,IPC_CREAT|0644);
共享内存的删除
删除共享内存调用shmctl函数
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
函数功能
共享内存控制函数,功能由具体的功能命令字决定
shmid:共享内存id
cmd:控制命令字
IPC_STAT:获取消息队列属性
IPC_SET:设置消息队列属性
IPC_RMID:删除消息队列属性,用此命名时,第三个参数为NULL
buf:共享内存属性结构体指针
#define PATH_NAME "."
#define PROJ_ID 110
#define SHM_SZ 102
int main()
{
key_t key = ftok(PATH_NAME,PROJ_ID);
if(key == -1)
{
perror("ftok");
exit(EXIT_FAILURE);
}
int shmid = shmget(key,SHM_SZ,IPC_CREAT|0644);
if(shmid==-1)
{
perror("shmget");
exit(EXIT_FAILURE);
}
return 0;
}
共享内存映射与解除映射
共享内存映射调用shmat函数
void *shmat(int shmid, const void *shmaddr, int shmflg);
函数功能
将进程地址空间映射到共享内存上
函数参数
shmid:共享内存id
shmaddr:指定映射到进程地址空间的起始地址,指定为NULL时,由系统选择映射的地址
shmflg:共享内存标志,一般设置为0
解除共享映射调用 shmdt 函数
int shmdt(const void *shmaddr);
函数功能解除进程地址空间与共享内存的映射
函数参数
shmaddr:映射地址空间的起始地址
//共享内存映射
void* addr = shmat(shmid,NULL,0);
if(addr == (void*)-1)
{
perror("shmat");
exit(EXIT_FAILURE);
}
char buf[1024]={0};
memcpy(buf,addr,10);
printf("share memory content:%s\n",buf);
shmdt(addr); // 解除绑定