目录
1. 消息队列
1.1 消息队列特点
1.2 消息队列相关函数
1.3 ftok 函数
1.4 消息队列实现全双工通信
1.4.1 msg_service.c
1.4.2 msg_client.c
1.4.3 程序运行结果:
2. 共享内存
2.1 共享内存概念
2.2 相关函数
2.3 共享内存特点
2.4 共享内存实现两进程通信
2.4.1 shmWrite.c
2.4.2 shmRead.c
2.4.3 程序运行结果:
消息队列,是消息的链表,存放在内核中,一个消息队列由一个标识符(队列ID)来标识。
1. int msgget(key_t key, int msgflg);
//创建或打开消息队列,
参数:
key:和消息队列关联的 key 值
msgflg:是一个权限标志,表示消息队列的访问权限,它与文件的访问权限一样。 msgflg 可以与 IPC_CREAT 做或操作,表示当 key 所命名的消息队列不存在时创建一个消息队列,如果 key 所命名的消息队列存在时,IPC_CREAT 标志会被忽略,而只返回一个标识符。
返回值:成功返回队列 ID,失败则返回‐1,
在以下两种情况下,msgget 将创建一个新的消息队列:
2.int msgsnd(int msgid, const void *msgp, size_t msgsize, int msgflg);
//读取消息,成功返回消息数据的长度,失败返回‐1
参数:
msgid:消息队列的 ID
msgp:指向消息的指针,常用结构体 msgbuf 如下:
struct msgbuf
{
long mtype; //消息类型
char mtext[N]; //消息正文
}
size:发送的消息正文你的字节数
flag: IPC_NOWAIT: 消息没有发送完成函数也会立即返回
0: 直到发送完成函数才返回
返回值: 成功:0
失败:‐1
3.ssize_t msgrcv(int msgid, void *msgp, size_t msgsize, long msgtype, int msgflag);
//从一个消息队列中获取消息
参数:
msgid:消息队列的 ID
msgp:要接收消息的缓冲区
size:要接收的消息的字节数
msgtype:
0:接收消息队列中第一个消息
大于0:接收消息队列中第一个类型为 msgtyp 的消息
小于0:接收消息队列中类型值不大于 msgtyp 的绝对值且类型值又最小的消息。
flag:
0:若无消息函数一直阻塞
IPC_NOWAIT:若没有消息,进程会立即返回 ENOMSG。
返回值:
成功:接收到的消息i长度
出错:‐1
4.int msgctl(int msgid, int cmd, struct msgid_ds *buf);
//控制消息队列,成功返回0,失败返回‐1
参数:
msqid:消息队列的队列ID
cmd:
IPC_STAT:把 msgid_ds 结构中的数据设置为消息队列的当前关联值,即用消息队列的当前关联值覆盖 msgid_ds 的值。
IPC_SET:如果进程有足够的权限,就把消息列队的当前关联值设置为 msgid_ds 结构中给出的值
IPC_RMID:删除消息队列
buf:是指向 msgid_ds 结构的指针,它指向消息队列模式和访问权限的结构
返回值:
成功:0
失败:‐1
key_t ftok( char * fname, int id )
//系统建立IPC通讯(如消息队列、共享内存时)必须指定一个ID值。该id值通过 ftok 函数得到。
参数:
fname就时你指定的文件名(该文件必须是存在而且可以访问的)。
id是子序号, 虽然为int,但是只有8个比特被使用(0‐255)。
返回值:
当成功执行的时候,一个 key_t 值将会被返回,否则 ‐1 被返回。
#include
#include
#include
#include
#include
#include
#include
struct msgbuf // 消息队列结构体
{
long mtype;
char mtext[128];
char ID[4];
};
int main()
{
struct msgbuf sendbuf, readbuf;
int msgId;
key_t key;
int readret;
pid_t pid;
key = ftok("a.c", 1); // 获取 key 值
msgId = msgget(key, IPC_CREAT | 0755); // 创建消息队列
if (msgId == -1)
{
printf("create message queue failed!~\n");
perror("msgget");
return -1;
}
printf("create msgage queue succeeded!~ msgId = %d\n", msgId);
system("ipcs -q"); // 显示当前消息队列信息
// init msgbuf
sendbuf.mtype = 100;
pid = fork();
// parent process write 100
if (pid > 0)
{
while (1)
{
memset(sendbuf.mtext, 0, 128);
printf("please input to message queue:\n");
fgets(sendbuf.mtext, 128, stdin);
// send message to message queue
msgsnd(msgId, (void *)&sendbuf, strlen(sendbuf.mtext), 0);
}
}
// child process read 200
if (pid == 0)
{
while (1)
{
memset(readbuf.mtext, 0, 128);
msgrcv(msgId, (void *)&readbuf, 128, 200, 0);
printf("datas from client: %s\n", readbuf.mtext);
}
}
return 0;
}
#include
#include
#include
#include
#include
#include
#include
struct msgbuf // 消息队列结构体
{
long mtype;
char mtext[128];
char ID[4];
};
int main()
{
struct msgbuf sendbuf, readbuf;
int msgId;
key_t key;
int readret;
pid_t pid;
key = ftok("a.c", 1); // 获取 key 值
msgId = msgget(key, IPC_CREAT | 0755); // 创建消息队列
if (msgId == -1)
{
printf("create message queue failed!~\n");
perror("msgget");
return -1;
}
printf("create msgage queue succeeded!~ msgId = %d\n", msgId);
system("ipcs -q"); // 显示当前消息队列信息
// init msgbuf
sendbuf.mtype = 200;
pid = fork();
// child process write 200
if (pid == 0)
{
while (1)
{
memset(sendbuf.mtext, 0, 128);
printf("please input to message queue:\n");
fgets(sendbuf.mtext, 128, stdin);
// send message to message queue
msgsnd(msgId, (void *)&sendbuf, strlen(sendbuf.mtext), 0);
}
}
// parent process read 100
if (pid > 0)
{
while (1)
{
memset(readbuf.mtext, 0, 128);
msgrcv(msgId, (void *)&readbuf, 128, 100, 0);
printf("datas from service: %s\n", readbuf.mtext);
}
}
return 0;
}
共享内存(Shared Memory)就是允许多个进程访问同一个内存空间,是在多个进程之间共享和传递数据最高效的方式。操作系统将不同进程之间共享内存安排为同一段物理内存,进程可以将共享内存连接到它们自己的地址空间中,如果某个进程修改了共享内存中的数据,其它的进程读到的数据也将会改变。
1.int shmget(key_t key, size_t size, int shmflg);
//用来获取或创建共享内存
参数:
key:IPC_PRIVATE 或 ftok 的返回值
size:共享内存区大小
shmflg:同 open 函数的权限位,也可以用8进制表示法
返回值:
成功:共享内存段标识符‐‐‐ID‐‐‐文件描述符
出错:‐1
2.void *shmat(int shm_id, const void *shm_addr, int shmflg);
//把共享内存连接映射到当前进程的地址空间
参数:
shm_id:ID号
shm_addr:映射到的地址,NULL 为系统自动完成的映射
shmflg:
SHM_RDONLY 共享内存只读
默认是 0,表示共享内存可读写
返回值:
成功:映射后的地址
失败:NULL
3.int shmdt(const void *shmaddr);
//将进程里的地址映射删除
参数:
shmid:要操作的共享内存标识符
返回值:
成功:0
出错:‐1
4.int shmctl(int shm_id, int command, struct shmid_ds *buf);
//删除共享内存对象
参数:
shmid:要操作的共享内存标识符
command :
IPC_STAT (获取对象属性)‐‐‐ 实现了命令ipcs ‐m
IPC_SET (设置对象属性)
IPC_RMID (删除对象) ‐‐‐实现了命令ipcrm ‐m
buf :指定 IPC_STAT/IPC_SET 时用以保存/设置属性
返回值:
成功:0
出错:‐1
#include
#include
#include
#include
#include
#include
#include
int main()
{
int shmId;
int key;
char *p;
key = ftok("a.c", 1); // 生成 key 值
if (key < 0)
{
perror("ftok");
return -1;
}
printf("ftok succeed!~ key = %x\n", key);
shmId = shmget(key, 128, IPC_CREAT | 0777); // 创建共享内存
if (shmId < 0)
{
perror("share memory:");
return -1;
}
printf("create share memory succeeded!~ shmId = %d\n", shmId);
system("ipcs -m");
p = (char *)shmat(shmId, NULL, 0); // 共享内存映射,配置可读可写的方式由系统自动映射
if (p == NULL)
{
perror("share memory function");
return -1;
}
memset(p, 0, 128);
// write to share memory
while (1)
{
fgets(p, 128, stdin);
}
return 0;
}
#include
#include
#include
#include
#include
#include
#include
int main()
{
int shmId;
int key;
char *p;
key = ftok("a.c", 1);
if (key < 0)
{
perror("ftok");
return -1;
}
printf("ftok succeed!~ key = %x\n", key);
shmId = shmget(key, 128, 0);
if (shmId < 0)
{
perror("share memory:");
return -1;
}
printf("create share memory succeeded!~ shmId = %d\n", shmId);
system("ipcs -m");
p = (char *)shmat(shmId, NULL, 0);
if (p == NULL)
{
perror("share memory function");
return -1;
}
while (1)
{
sleep(5);
printf("share memory data = %s\n", p);
memset(p, 0, 128);
}
// shmdt(p);
return 0;
}