一、相关练习
1.使用消息队列完成两个进程之间相互通信
1.1> msg1.c
#include <myhead.h>
//要发送的消息类型
struct msgbuf
{
long mtype;
char mtext[1024];
};
int main(int argc, char const *argv[])
{
//1、创建key值,用于标识消息队列
key_t key = ftok("/", 'k');
if(-1 == key)
{
perror("ftok error");
return -1;
}
//2、通过key值创建一个消息队列
int msqid = msgget(key, IPC_CREAT|0664);
if(-1 == msqid)
{
perror("megget error");
return -1;
}
//创建父子进程
pid_t pid = fork();
if(pid < 0)
{
perror("fork error");
return -1;
}else if(pid == 0)
{
//子进程
//4.从消息队列中读取消息
struct msgbuf rbuf;
rbuf.mtype = 2;
while(1)
{
msgrcv(msqid, &rbuf, sizeof(rbuf.mtext), 2, 0);
if(strcmp(rbuf.mtext, "quit") == 0)
{
printf("B请求关闭聊天,请输入quit确认\n");
//退出子进程
exit(EXIT_SUCCESS);
}
printf("收到B的消息:%s\n", rbuf.mtext);
}
}
//3、向消息队列中存放消息
struct msgbuf wbuf;
wbuf.mtype = 1;
while(1)
{
printf("向B发送消息:\n");
fgets(wbuf.mtext, sizeof(wbuf.mtext), stdin); //从终端读取数据
wbuf.mtext[strlen(wbuf.mtext)-1] = 0; //去掉换行符
//向消息队列中存放消息
msgsnd(msqid, &wbuf, sizeof(wbuf.mtext), 0);
if(strcmp(wbuf.mtext, "quit") == 0)
{
break;
}
}
//回收子进程
wait(NULL);
//5、删除消息队列
if(msgctl(msqid, IPC_RMID, NULL) == -1)
{
perror("msgctl error");
return -1;
}
return 0;
}
1.2> msg2.c
#include <myhead.h>
//要发送的消息类型
struct msgbuf
{
long mtype;
char mtext[1024];
};
int main(int argc, char const *argv[])
{
//1、创建key值,用于标识消息队列
key_t key = ftok("/", 'k');
if(-1 == key)
{
perror("ftok error");
return -1;
}
//2、通过key值创建一个消息队列
int msqid = msgget(key, IPC_CREAT|0664);
if(-1 == msqid)
{
perror("megget error");
return -1;
}
//创建父子进程
pid_t pid = fork();
if(pid < 0)
{
perror("fork error");
return -1;
}else if(pid == 0)
{
//子进程
//4.从消息队列中读取消息
struct msgbuf rbuf;
rbuf.mtype = 1;
while(1)
{
msgrcv(msqid, &rbuf, sizeof(rbuf.mtext), 1, 0);
if(strcmp(rbuf.mtext, "quit") == 0)
{
printf("A请求关闭聊天,请输入quit确认\n");
//退出子进程
exit(EXIT_SUCCESS);
}
printf("收到A的消息:%s\n", rbuf.mtext);
}
}
//3、向消息队列中存放消息
struct msgbuf wbuf;
wbuf.mtype = 2;
while(1)
{
printf("向A发的消息:\n");
fgets(wbuf.mtext, sizeof(wbuf.mtext), stdin); //从终端读取数据
wbuf.mtext[strlen(wbuf.mtext)-1] = 0; //去掉换行符
//向消息队列中存放消息
msgsnd(msqid, &wbuf, sizeof(wbuf.mtext), 0);
if(strcmp(wbuf.mtext, "quit") == 0)
{
break;
}
}
//回收子进程
wait(NULL);
//5、删除消息队列
if(msgctl(msqid, IPC_RMID, NULL) == -1)
{
perror("msgctl error");
return -1;
}
return 0;
}
1.3> 程序运行效果
![](https://i-blog.csdnimg.cn/direct/d91e1e13fad842f5834d94762618bb54.png)
2.将共享内存的实现重新敲一遍
1.1> shmsnd.c
#include <myhead.h>
int main(int argc, const char *argv[])
{
//1、创建key值,用于初始化共享内存
key_t key = ftok("/", 'k');
if(-1 == key)
{
perror("ftok error");
return -1;
}
printf("key = %#x\n", key);
//2、通过key值初始化一个共享内存
int shmid = shmget(key, PAGE_SIZE, IPC_CREAT|0664);
if(-1 == shmid)
{
perror("shmget error");
return -1;
}
printf("shmid = %d\n", shmid);
//3、将共享内存映射到程序中
char *shmaddr = (char *)shmat(shmid, NULL, 0);
//参数1:共享内存id号
//参数2:系统自动映射对齐页
//参数3:表示对共享内存的操作权限为读写权限
printf("shmaddr = %p\n", shmaddr);
//向共享内存中写入数据
strcpy(shmaddr, "hello a hua qing yuan jian\n");
sleep(5);
//4、取消映射关系
if(shmdt(shmaddr) == -1)
{
perror("shmdt error");
return -1;
}
getchar(); //阻塞
return 0;
}
1.2> shmrecv.c
#include <myhead.h>
int main(int argc, const char *argv[])
{
//1、创建一个key,用于初始化共享内存对象
key_t key = ftok("/", 'k');
if(-1 == key)
{
perror("ftok error");
return -1;
}
printf("key = %#x\n", key);
//2、使用key初始化一个共享内存对象
int shmid = shmget(key, PAGE_SIZE, IPC_CREAT|0664);
if(-1 == shmid)
{
perror("shmget error");
return -1;
}
printf("shmid = %d\n", shmid);
//3、将共享内存对象映射到当前程序中
char *shmaddr = (char*)shmat(shmid, NULL, 0);
if(NULL == shmaddr)
{
perror("shmat error");
return -1;
}
//输出共享内存中的数据
printf("shmaddr = %s\n", shmaddr);
//4、取消共享内存映射
if(shmdt(shmaddr) == -1)
{
perror("shmdt error");
return -1;
}
//5、删除共享内存
if(shmctl(shmid, IPC_RMID, NULL) == -1)
{
perror("shmctl error");
return -1;
}
getchar(); //阻塞
return 0;
}
1.3> 程序运行效果
![](https://i-blog.csdnimg.cn/direct/7a74d9da7b4f443baeda3d9c5a890599.png)
二、思维导图
![](https://i-blog.csdnimg.cn/direct/b806506ea92541ffbfa12cd7d0e982eb.png)