进程间通信练习题
进行一些进程通信的练习题分享
第一题
创建不相关的两个进程(P1,P2),要求,P1 将自身的PID 写入命名管道,P2 从命名管道中获取P1的PID,P2 向 P1 发送携带数据的信号 SIGUSR1,P1 接收到信号后,获取传递的数据,在数据指定的秒数过后退出。
P1端
#include "head.h"
#define PATH "/home/st/fifofile"//此路径可以改变
void handler(int sig, siginfo_t *info, void *a)
{
if (sig == SIGUSR1)
{
printf("recv a sig = %d, 已获取pid = %d的信号\n", sig, info->si_value.sival_int);
sleep(3);
kill(getpid(), 9);
}
}
int main(int argc, char const *argv[])
{
if (mkfifo(PATH, 0777) == -1)
{
// 根据错误进行判断若管道文件已经存在不报错
if (errno != EEXIST)
{
perror("mkfifo()");
exit(1);
}
}
char buf[10];
// 获取该进程pid并转换成字符串
snprintf(buf, sizeof(buf), "%d", getpid());
printf("%d---%s", getpid(), buf);
int fd = open(PATH, O_RDWR);
if (!fd)
{
perror("open()");
return -1;
}
if (write(fd, buf, strlen(buf)) == -1)
{
perror("write()");
return -1;
}
close(fd);
struct sigaction avt;
// 清空信号集
sigemptyset(&avt.sa_mask);
avt.sa_sigaction = handler;
avt.sa_flags = SA_SIGINFO;
int r = sigaction(SIGUSR1, &avt, NULL);
if (r == -1)
{
perror("sigaction()");
return -1;
}
puts("等待信号!");
pause();
return 0;
}
P2端
#include "head.h"
#define PATH "/home/st/fifofile"//此路径可以改变
int main(int argc, char const *argv[])
{
if (mkfifo(PATH, 0777) == -1)
{
// 根据错误进行判断若管道文件已经存在不报错
if (errno != EEXIST)
{
perror("mkfifo()");
exit(1);
}
}
char buf[10];
int fd = open(PATH, O_RDWR);
if (!fd)
{
perror("open()");
return -1;
}
if (read(fd, buf, sizeof(buf)) == -1)
{
perror("write()");
return -1;
}
union sigval val;
val.sival_int = getpid();
sigqueue(atoi(buf), SIGUSR1, val);
close(fd);
return 0;
}
第二题
两个没有亲缘关系的进程之间通过消息队列实现简单的聊天,要求创建消息队列的进程若先退出,给另一个进程通知,另一个进程得到通知后回收消息队列,并退出
发送端:
#include "head.h"
#define PATH "home/st/msgfile"
void fun(int sig)
{
printf("%d\n", sig);
kill(getpid(), 9);
}
typedef struct
{
long type; // 接收端通过标记访问
int pid; // 传递pid
char data[100]; // 数据
} msg_t;
int main(int argc, char const *argv[])
{
// 通过文件路径和一个整数获取一个key
key_t key = ftok(PATH, 222);
// 创建消息队列
int msgid = msgget(key, IPC_CREAT | 0777);
if (msgid == -1)
{
perror("msgget()");
return -1;
}
// 定义要发送的信息数组
char data[100] = {0};
// 创建数据块对应的结构体成员
msg_t msg = {0};
while (1)
{
int vpid = 0; // 存放对方的pid便于后续退出
msg.pid = getpid(); // 将发送端pid传递给接收端
// 设置消息的类型
msg.type = 1;
// 清理上次发送消息的内容
memset(data, 0, sizeof(data));
// 清理消息中的数据
memset(msg.data, 0, sizeof(msg.data));
printf("请输入:");
// 键盘输入要发送的字符串
fgets(data, sizeof(data), stdin);
// 将用户输入的内容拷贝到结构体的成员上
strcpy(msg.data, data);
// 调用发送函数发送数据块
int r = msgsnd(msgid, &msg, sizeof(msg), 0);
// 发送端接收接收端发送过来的数据
ssize_t r1 = msgrcv(msgid, &msg, sizeof(msg), 2, 0);
printf("接收端的消息:%s", msg.data);
vpid = msg.pid;
if (r1 == 0 || strcmp(msg.data, "bye\n") == 0)
{
// 调用定时器函数
alarm(1);
// 给定时器绑定处理函数
signal(SIGALRM, fun);
}
}
// 销毁消息队列
msgctl(msgid, IPC_RMID, NULL);
return 0;
}
接收端:
#include "head.h"
#define PATH "home/st/msgfile"
typedef struct
{
long type; // 接收端通过标记访问
int pid; // 传递pid
char data[100]; // 数据
} msg_t;
int main(int argc, char const *argv[])
{
// 通过文件路径和一个整数获取一个key
key_t key = ftok(PATH, 222);
// 创建消息队列
int msgid = msgget(key, IPC_CREAT | 0777);
if (msgid == -1)
{
perror("msgget()");
return -1;
}
// 创建接收数据块的结构体遍历
msg_t msg = {0};
msg.pid = getpid();
// 定义要发送的信息数组
char data[100] = {0};
while (1)
{
// 调用接收函数接收发送过来的数据
ssize_t r1 = msgrcv(msgid, &msg, sizeof(msg), 1, 0);
printf("发送端的数据:%s", msg.data);
if (r1 == 0 || strcmp(msg.data, "bye\n") == 0)
{
break;
}
// 设置消息的类型
msg.type = 2;
// 清理上次发送消息的内容
memset(data, 0, sizeof(data));
// 清理消息中的数据
memset(msg.data, 0, sizeof(msg.data));
printf("请输入:");
// 键盘输入要发送的字符串
fgets(data, sizeof(data), stdin);
// 将用户输入的内容拷贝到结构体的成员上
strcpy(msg.data, data);
// 调用发送函数发送数据块
int r = msgsnd(msgid, &msg, sizeof(msg), 0);
if (r == -1 || strcmp(data, "bye\n") == 0)
{
break;
}
}
// 销毁消息队列
msgctl(msgid, IPC_RMID, NULL);
return 0;
}