消息队列,共享内存

This commit is contained in:
flykhan 2023-08-18 16:47:04 +08:00
parent e6757b9935
commit 49d2f0cabb
12 changed files with 594 additions and 0 deletions

46
day5/consumer.c Normal file
View File

@ -0,0 +1,46 @@
// 消费者
#include <stdio.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <unistd.h>
typedef struct data
{
char data[32];
int flag;
} Data;
int main()
{
printf("consumer\n");
key_t key = ftok("/", 15);
if (key == -1)
{
perror("ftok");
return 1;
}
int shmid = shmget(key, sizeof(Data), IPC_CREAT | 0666);
if (shmid == -1)
{
perror("shmget");
return 1;
}
Data *data_buf = (Data *)shmat(shmid, NULL, 0);
if (data_buf == (Data *)-1)
{
perror("shmat");
return 1;
}
while (1)
{
while (data_buf->flag == 0)
;
sleep(1);
printf("read data: %s\n", data_buf->data);
data_buf->flag = 0;
}
return 0;
}

25
day5/ftok1.c Normal file
View File

@ -0,0 +1,25 @@
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
// ftok()函数用于获取消息队列的键值
int main()
{
// 获取消息队列的键值返回值是一个整数表示消息队列IPC的键值
key_t key = ftok("/", 26);
printf("key = %d\n", key);
// ftok()函数的第一个参数是路径,第二个参数是索引值
// 索引值是一个整数范围是0~255用于区分不同的消息队列
// 超过255的索引值会被截断例如256会被截断为0257会被截断为1相当于循环使用
key_t key2 = ftok("/", 26);
printf("key = %d\n", key2);
int mask = 0xff; // 0b11111111 低8位掩码
printf("mask = %d\n", mask);
// 低8位掩码与key进行与运算得到低8位
printf("key & mask = %d\n", key & mask); // 用于获取低8位
printf("key2 & mask = %d\n", key2 & mask); // 用于获取低8位
return 0;
}

31
day5/msgque1.c Normal file
View File

@ -0,0 +1,31 @@
#include <stdio.h>
#include <sys/types.h> // 系统数据类型定义
#include <sys/ipc.h> // IPC相关头文件
#include <sys/msg.h> // 消息队列相关头文件
// msgget 函数用于创建消息队列参数1是键值参数2是权限
int main()
{
key_t key = ftok("/home/flykhan/", 200); // 获取消息队列的键值
printf("key = %d\n", key);
if (key == -1)
{
perror("ftok");
return 1;
}
// msgget 函数用于创建消息队列参数1是键值参数2是权限
// 返回值是消息队列的标识符,类似于文件描述符
// IPC_CREAT 表示如果消息队列不存在则创建,如果存在则打开
// 0644 表示权限,类似于文件权限,表示所有者可读写,其他人只读
int msgqid = msgget(key, IPC_CREAT | 0666); // 创建消息队列
if (msgqid == -1)
{
perror("msgget");
return 1;
}
// msgqid 只要不是 -1 就表示创建成功
printf("msgqid = %d\n", msgqid); // 打印消息队列标识符
return 0;
}

102
day5/msgque4.c Normal file
View File

@ -0,0 +1,102 @@
#include <stdio.h>
#include <sys/types.h> // 系统数据类型定义
#include <sys/ipc.h> // IPC相关头文件
#include <sys/msg.h> // 消息队列相关头文件
#include <string.h> // 字符串操作
#include <stdlib.h> // atol 函数
#include <time.h> // 时间函数
#include <unistd.h> // 头文件含义unix standard即unix标准的意思
// 消息结构体
typedef struct msg_
{
long mType; // 消息类型,必须是 long ,必须在第一个位置
char content[100]; // 消息内容,需要小于消息队列的限制值(8192)
char title[32]; // 消息标题
} MSG;
// msgget 函数用于创建消息队列参数1是键值参数2是权限
int main(int argc, char *argv[])
{
key_t key = ftok("/", 200); // 获取消息队列的键值
int msgqid = msgget(key, IPC_CREAT | 0666); // 创建消息队列
if (msgqid == -1)
{
perror("msgget");
return 1;
}
// 查看 msgqid 消息队列的信息
struct msqid_ds msginfo; // 消息队列信息结构体
int ret = msgctl(msgqid, IPC_STAT, &msginfo); // 获取消息队列信息
if (ret == -1)
{
perror("msgctl");
return 1;
}
time_t st = msginfo.msg_stime; // 最后发送消息的时间
time_t rt = msginfo.msg_rtime; // 最后接收消息的时间
time_t ct = msginfo.msg_ctime; // 最后变更消息的时间
struct tm *stm = localtime(&st); // 转换为北京时间
struct tm *rtm = localtime(&rt); // 转换为北京时间
struct tm *ctm = gmtime(&ct); // 转换为北京时间
// // 手动转换为北京时间
// st += 8 * 60 * 60;
// rt += 8 * 60 * 60;
// ct += 8 * 60 * 60;
// // 把时间戳转换为字符串
// char stime[32] = "";
// char rtime[32] = "";
// char ctime[32] = "";
// ctime_r(&st, stime);
// ctime_r(&rt, rtime);
// ctime_r(&ct, ctime);
// // 打印时间
// printf("最后发送消息的时间: %s", stime);
// printf("最后接收消息的时间: %s", rtime);
// printf("最后变更消息的时间: %s", ctime);
// printf("最后变更消息的时间: %s", ctime);
// + 1900 是因为 struct tm 结构体中的 tm_year 字段表示的是从1900年开始的年数的偏移量。
// +1 是因为 struct tm 结构体中的 tm_mon 字段表示的是月份的偏移量范围是0-11其中0表示一月11表示十二月
printf("最后发送消息的时间: %d-%d-%d %d:%d:%d\n", stm->tm_year + 1900, stm->tm_mon + 1, stm->tm_mday, stm->tm_hour, stm->tm_min, stm->tm_sec);
printf("最后接收消息的时间: %d-%d-%d %d:%d:%d\n", rtm->tm_year + 1900, rtm->tm_mon + 1, rtm->tm_mday, rtm->tm_hour, rtm->tm_min, rtm->tm_sec);
printf("最后变更消息的时间: %d-%d-%d %d:%d:%d\n", ctm->tm_year + 1900, ctm->tm_mon + 1, ctm->tm_mday, ctm->tm_hour, ctm->tm_min, ctm->tm_sec);
// 打印消息队列的信息
printf("\n消息队列的信息:\n");
printf("消息队列的标识符: %d\n", msginfo.msg_perm.__key);
printf("消息队列的权限: %04o\n", msginfo.msg_perm.mode); // %04o 是八进制输出占4位不足4位前面补0
// 修改消息队列的权限
// msginfo.msg_perm.mode = 0644; // 修改权限
msginfo.msg_perm.mode |= 0111; // 修改权限,增加可执行权限
ret = msgctl(msgqid, IPC_SET, &msginfo);
if (ret == -1)
{
perror("msgctl");
return 1;
}
printf("修改消息队列的权限为: %04o\n", msginfo.msg_perm.mode); // %04o 是八进制输出占4位不足4位前面补0
// execlp("ipcs", "ipcs", "-q", NULL); // 打印消息队列
// 减少权限
msginfo.msg_perm.mode &= ~0101; // 修改权限,减少可执行权限
ret = msgctl(msgqid, IPC_SET, &msginfo);
if (ret == -1)
{
perror("msgctl");
return 1;
}
printf("修改消息队列的权限为: %04o\n", msginfo.msg_perm.mode); // %04o 是八进制输出占4位不足4位前面补0
execlp("ipcs", "ipcs", "-q", NULL); // 打印消息队列
return 0;
}

29
day5/msgque_msgctl_test.c Normal file
View File

@ -0,0 +1,29 @@
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
// 测试 msgctl ,用于删除消息队列
int main()
{
key_t key = ftok("/", 65); // 使用ftok函数生成一个唯一的键值
int msqid = msgget(key, 0666 | IPC_CREAT); // 创建或获取消息队列
if (msqid == -1)
{
perror("msgget");
exit(1);
}
// 控制操作:删除消息队列
if (msgctl(msqid, IPC_RMID, NULL) == -1)
{
perror("msgctl");
exit(1);
}
printf("Message queue removed successfully.\n");
return 0;
}

47
day5/producer.c Normal file
View File

@ -0,0 +1,47 @@
// 生产者
#include <stdio.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <unistd.h>
typedef struct data
{
char data[32];
int flag;
} Data;
int main()
{
printf("producer\n");
key_t key = ftok("/", 15);
if (key == -1)
{
perror("ftok");
return 1;
}
int shmid = shmget(key, sizeof(Data), IPC_CREAT | 0666);
if (shmid == -1)
{
perror("shmget");
return 1;
}
Data *data_buf = (Data *)shmat(shmid, NULL, 0);
if (data_buf == (Data *)-1)
{
perror("shmat");
return 1;
}
int num = 0;
while (1)
{
while (data_buf->flag == 1)
;
sprintf(data_buf->data, "hello, %d", num++);
data_buf->flag = 1;
printf("write data: %s\n", data_buf->data);
}
return 0;
}

30
day5/shm1.c Normal file
View File

@ -0,0 +1,30 @@
// 共享内存
/*
"shm"shared memory
Linux系统中使`shmget`shared memory segment
"shm""share mem"使
*/
#include <sys/shm.h>
#include <stdio.h>
#include <sys/types.h>
int main()
{
key_t key = ftok("/", 28);
// 获取共享内存的标识
int shmid = shmget(key, 32, IPC_CREAT | 0666);
if (shmid == -1)
{
perror("shmget");
return 1;
}
printf("shmid=%d\n", shmid);
return 0;
}

44
day5/shm2.c Normal file
View File

@ -0,0 +1,44 @@
// 共享内存
#include <sys/shm.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
// 共享内存写数据
int main()
{
key_t key = ftok("/", 28);
// 获取共享内存的标识
int shmid = shmget(key, 32, IPC_CREAT | 0666);
if (shmid == -1)
{
perror("shmget");
return 1;
}
printf("shmid=%d\n", shmid);
// 获取共享内存的首地址
char *buf = shmat(shmid, NULL, 0); // NULL表示让系统自动分配共享内存的首地址
if (buf == (char *)-1)
{
perror("shmat");
return 1;
}
strcpy(buf, "hi, shared memory");
printf("write data ok\n");
/*
// 删除共享内存
int ret = shmctl(shmid, IPC_RMID, NULL); // 删除共享内存
if (ret == -1)
{
perror("shmctl");
return 1;
}
printf("shared memory deleted\n");
*/
return 0;
}

42
day5/shm3.c Normal file
View File

@ -0,0 +1,42 @@
// 共享内存
#include <sys/shm.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
// 共享内存读数据
int main()
{
key_t key = ftok("/", 28);
// 获取共享内存的标识
int shmid = shmget(key, 32, IPC_CREAT | 0666);
if (shmid == -1)
{
perror("shmget");
return 1;
}
printf("shmid=%d\n", shmid);
// 获取共享内存的首地址
char *buf = shmat(shmid, NULL, 0); // NULL表示让系统自动分配共享内存的首地址
if (buf == (char *)-1)
{
perror("shmat");
return 1;
}
printf("共享内存的数据:%s\n", buf);
/*
// 删除共享内存
int ret = shmctl(shmid, IPC_RMID, NULL); // 删除共享内存
if (ret == -1)
{
perror("shmctl");
return 1;
}
printf("shared memory deleted\n");
*/
return 0;
}

42
day5/shm4.c Normal file
View File

@ -0,0 +1,42 @@
// 共享内存
#include <sys/shm.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
// 解除映射
int main()
{
key_t key = ftok("/", 28);
// 获取共享内存的标识
int shmid = shmget(key, 32, IPC_CREAT | 0666);
if (shmid == -1)
{
perror("shmget");
return 1;
}
printf("shmid=%d\n", shmid);
// 获取共享内存的首地址
char *buf = shmat(shmid, NULL, 0); // NULL表示让系统自动分配共享内存的首地址
if (buf == (char *)-1)
{
perror("shmat");
return 1;
}
printf("共享内存的数据:%s\n", buf);
// 解除映射
int ret = shmdt(buf);
if (ret == -1)
{
perror("shmdt");
return 1;
}
printf("解除映射成功 ok\n");
return 0;
}

47
day5/shm5.c Normal file
View File

@ -0,0 +1,47 @@
// 共享内存
#include <sys/shm.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
// 共享内存删除
int main()
{
key_t key = ftok("/", 28);
// 获取共享内存的标识
int shmid = shmget(key, 32, IPC_CREAT | 0666);
if (shmid == -1)
{
perror("shmget");
return 1;
}
printf("shmid=%d\n", shmid);
// 获取共享内存的首地址
char *buf = shmat(shmid, NULL, 0); // NULL表示让系统自动分配共享内存的首地址
if (buf == (char *)-1)
{
perror("shmat");
return 1;
}
printf("共享内存的数据:%s\n", buf);
// 删除共享内存
// NULL 表示不关心共享内存的信息
// int ret = shmctl(shmid, IPC_RMID, NULL); // 删除共享内存
// 如果不写 NULL应该写一个结构体表示共享内存的信息
struct shmid_ds ds;
int ret = shmctl(shmid, IPC_RMID, &ds); // 删除共享内存
if (ret == -1)
{
perror("shmctl");
return 1;
}
printf("shared memory deleted\n");
return 0;
}

109
day5/shm6.c Normal file
View File

@ -0,0 +1,109 @@
#include <stdio.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <unistd.h>
#include <sys/wait.h>
typedef struct data
{
int data;
int flag;
} Data;
int main()
{
key_t key = ftok("/", 28);
int shmid = shmget(key, sizeof(Data), IPC_CREAT | 0666);
if (shmid == -1)
{
perror("shmget");
return 1;
}
if (fork() == 0) // 生产者进程
{
Data *data = shmat(shmid, NULL, 0);
if (data == (Data *)-1)
{
perror("shmat");
return 1;
}
data->flag = 0; // 初始化为 0
data->data = 0; // 初始化为 0
for (int i = 0; i < 100; i++)
{
// 等待消费者消费数据
while (data->flag == 1)
;
data->data++; // 生产数据
data->flag = 1;
printf("生产者生产数据:%d\n", data->data);
}
// 解除映射
if (shmdt(data) == -1)
{
perror("shmdt");
return 1;
}
_exit(0); // 子进程退出
}
if (fork() == 0) // 消费者进程
{
Data *data = shmat(shmid, NULL, 0);
if (data == (Data *)-1)
{
perror("shmat");
return 1;
}
data->flag = 0; // 初始化为 0
data->data = 0; // 初始化为 0
for (int i = 0; i < 100; i++)
{
// 等待生产者生产数据
while (data->flag == 0)
{
printf("等待生产者生产数据\n");
}
printf("消费者消费数据:%d\n", data->data);
// 消费到 100 时退出
if (data->data == 10)
break;
sleep(1);
data->flag = 0;
}
// 解除映射
if (shmdt(data) == -1)
{
perror("shmdt");
return 1;
}
_exit(0); // 子进程退出
}
while (1)
{
// WUNTRACED 不跟踪 ?
int pid = waitpid(0, NULL, WUNTRACED);
if (pid == -1)
{
break;
}
printf("%d 子进程结束\n", pid);
}
// 删除共享内存
if (shmctl(shmid, IPC_RMID, NULL) == -1)
{
perror("shmctl");
return 1;
}
return 0;
}