练习1:消息队列
请使用消息队列实现2个终端之间互相聊天
#发送端
key_t key;
int id;
typedef struct Msgbuf{
long channel;
char buf[128];
}msg_t;
int main(int argc, const char *argv[])
{
if (argc<2)
{
printf("传入频道号\n");
return 1;
}
key=ftok("./ipc",2);
id=msgget(key,IPC_CREAT|0666);
int channel =atoi(argv[1]);
msg_t msg;
msg.channel=channel;
while(1)
{
memset(msg.buf,0,128);
printf("请输入:");
scanf("%s",msg.buf);
while(getchar()!=10);
msgsnd(id,&msg,strlen(msg.buf),0);
}
return 0;
}
接收端
key_t key;
int id;
typedef struct Msgbuf{
long channel;
char buf[128];
}msg_t;
int main(int argc, const char *argv[])
{
key=ftok("./ipc",2);
id=msgget(key,IPC_CREAT|0666);
int channel =0;
msg_t msg={0};
while(1)
{
memset(msg.buf,0,128);
printf("请输入频道号:");
scanf("%d",&channel);
while(getchar()!=10);
msgrcv(id,&msg,128,channel,IPC_NOWAIT);
printf("读到的消息为:%s\n",msg.buf);
}
return 0;
}
练习2:共享内存 信号灯集
请使用共享内存 + 信号灯集,实现2个进程之间互相聊天
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#define SHM_SIZE 64 // 共享内存大小
#define SEM_KEY 1234 // 信号灯集的键值
// 共享内存结构体
typedef struct shm {
char buf[SHM_SIZE]; // 存储消息
int ready; // 标记是否有新消息
} shm_t;
// 信号灯集
int semid;
int shmid;
shm_t *shm_addr;
// 信号灯操作结构
struct sembuf sb;
// 获取共享内存
void* shm_alloc(int size, int proj_id) {
key_t key = ftok("./ipc", proj_id);
if (key == -1) {
perror("ftok");
return NULL;
}
shmid = shmget(key, size, IPC_CREAT | 0666);
if (shmid == -1) {
perror("shmget");
return NULL;
}
shm_addr = (shm_t*)shmat(shmid, NULL, 0);
if (shm_addr == (shm_t*)-1) {
perror("shmat");
return NULL;
}
return shm_addr;
}
// 获取信号灯集
int sem_alloc() {
semid = semget(SEM_KEY, 2, IPC_CREAT | 0666); // 创建信号灯集,2个信号灯
if (semid == -1) {
perror("semget");
return -1;
}
// 初始化信号灯
semctl(semid, 0, SETVAL, 0); // 读信号灯,初始值为 0
semctl(semid, 1, SETVAL, 1); // 写信号灯,初始值为 1
return 0;
}
// 信号灯操作:P操作 (阻塞)
void sem_wait(int sem_num) {
sb.sem_num = sem_num;
sb.sem_op = -1; // P操作
sb.sem_flg = 0;
semop(semid, &sb, 1);
}
// 信号灯操作:V操作 (释放)
void sem_signal(int sem_num) {
sb.sem_num = sem_num;
sb.sem_op = 1; // V操作
sb.sem_flg = 0;
semop(semid, &sb, 1);
}
// 信号处理函数:清理共享内存和信号灯集
void cleanup(int signum) {
if (signum == SIGINT) {
// 卸载共享内存
shmdt(shm_addr);
shmctl(shmid, IPC_RMID, NULL);
// 删除信号灯集
semctl(semid, 0, IPC_RMID);
printf("Cleaned up and exiting...\n");
exit(0);
}
}
// 进程 1(发送消息)
void process_1() {
char msg[SHM_SIZE];
while (1) {
sem_wait(1); // 等待可以写入消息
printf("Process 1: Enter message: ");
fgets(msg, SHM_SIZE, stdin);
msg[strcspn(msg, "\n")] = 0; // 去掉末尾的换行符
// 将消息存储到共享内存
strncpy(shm_addr->buf, msg, SHM_SIZE);
shm_addr->ready = 1; // 设置 ready 标志,表示有新消息
sem_signal(0); // 通知进程 2 可以读取消息
}
}
// 进程 2(接收消息)
void process_2() {
while (1) {
sem_wait(0); // 等待进程 1 写入消息
if (shm_addr->ready) {
printf("Process 2: Received message: %s\n", shm_addr->buf);
shm_addr->ready = 0; // 重置 ready 标志
sem_signal(1); // 通知进程 1 可以继续写入消息
}
}
}
int main(int argc, const char *argv[]) {
signal(SIGINT, cleanup); // 捕获 SIGINT 信号清理资源
if (shm_alloc(sizeof(shm_t), 1) == NULL) {
return 1;
}
if (sem_alloc() == -1) {
return 1;
}
// 创建子进程,进程 1 和 进程 2
pid_t pid = fork();
if (pid == 0) {
// 子进程 2
process_2();
} else if (pid > 0) {
// 父进程 1
process_1();
} else {
perror("fork failed");
return 1;
}
return 0;
}