|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 .实验名称 进程通信 |
| 1. 实验目的 (1)理解进程间通信的概念和方法。 (2)掌握常用的Linux进程间通信的方法。 |
| 1. 实验内容 (1)编写C程序,使用Linux中的IPC机制,完成"石头、剪子、布"的游戏。 (2)修改上述程序,使之能够在网络上运行该游戏。 |
| 4. 实验原理或流程图 消息队列的概念: 消息队列是一种进程间通信机制,允许不同进程之间通过发送和接收消息来交换数据。 每个消息队列都有一个唯一的标识符(key),用于区分不同的队列。 消息队列的创建: 使用msgget()系统调用创建消息队列,需要提供键值(key)和权限(perm)。 IPC_CREAT标志用于创建一个新的消息队列,如果队列已存在则返回现有的队列。 0666是权限掩码,表示任何用户都可以读写消息队列。 消息结构: 消息队列中的消息通常包含一个long类型的消息类型(Type)和一个指向消息数据的指针。 在这份代码中,消息数据是自定义的结构体Game,包含轮次(Round)和消息类型(Type)。 发送消息: 使用msgsnd()系统调用向消息队列发送消息。 需要提供消息队列的标识符(msgid)、指向消息结构的指针、消息长度和标志位(0表示不截断消息)。 接收消息: 使用msgrcv()系统调用从消息队列接收消息。 需要提供消息队列的标识符(msgid)、指向消息结构的指针、消息长度、消息类型和标志位(0表示接收第一个消息)。 消息队列的操作: msgctl()系统调用用于控制消息队列,如删除消息队列(IPC_RMID)。 消息队列的删除: 在程序结束时,应该使用msgctl()系统调用删除消息队列,释放系统资源。 消息队列的同步: 消息队列本身不提供同步机制,需要通过其他方式(如信号量、互斥锁)来确保消息的发送和接收顺序。 消息队列的容量: 消息队列有一个最大消息数和每个消息的最大长度限制,这些限制取决于系统配置。 错误处理: 如果msgget()、msgsnd()或msgrcv()调用失败,它们会返回-1,并设置全局变量errno以指示错误类型 |
cpp
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct Game //游戏信息
{
int Round;
long Type;
};
void result_send(int num) //发送出拳信息
{
struct Game game;
game.Type = 1;
game.Round = rand() % 3;
msgsnd(num, &game, sizeof(int), 0);
}
int result_announce(int a, int b) //出拳结果的判断
{
if ((a + 1 == b) || (a - 3 == b))
return -1; //a胜b
else if (a == b)
return 0; //ab平局
else
return 1; //a负b
}
void writeFile(int *result_list, int len) //将每盘的结果存入文件
{
int count_A = 0;
int count_B = 0;
int pingju=0;
FILE *fin;
if( (fin = fopen( "result.txt", "w" )) == NULL )
printf( "This file wasn't opened" );
int i;
for (i = 0; i < len ; i++)
{
switch(result_list[i])
{
case -1 :{
count_A++;
fprintf(fin, "NO.%d:A win\n", i + 1);
printf("NO.%d:A win\n", i + 1);
break;
}
case 0 : {
pingju++;
fprintf(fin, "NO.%d:end in a draw\n", i + 1);
printf("NO.%d:end in a draw\n", i + 1);
break;
}
case 1 : {
count_B++;
fprintf(fin, "NO.%d:B win\n", i + 1);
printf("NO.%d:B win\n", i + 1);
break;
}
}
}
printf("\nThe final result is A win:%ds \nB win:%ds \nend in a draw %ds\n",count_A,count_B,pingju);
fprintf(fin, "\nThe final result is A win:%ds \nB win:%ds \nend in a draw %ds\n",count_A,count_B,pingju);
fclose(fin);
}
int main()
{
int times;
int key1 = 1234;
int key2 = 5678;
int *result_list;
pid_t pid1, pid2;
int msgid1,msgid2;
msgid1 = msgget(key1, IPC_CREAT | 0666); //创建消息队列
if(msgid1 == -1)
{
fprintf(stderr, "failed with error");
exit(EXIT_FAILURE);
}
msgid2 = msgget(key2, IPC_CREAT | 0666); //创建消息队列
if(msgid2 == -1)
{
fprintf(stderr, "failed with error");
exit(EXIT_FAILURE);
}
printf("Game start,please input rounds:");
scanf("%d", ×);
result_list=(int*)malloc(times*sizeof(int));
int i;
for (i = 0; i < times; i++)
{
pid1 = fork(); //创建选手1
if (pid1 == 0)
{
srand((unsigned)time(0) * 3000 ); //以时间为种子
result_send(msgid1); //生成选手1的出拳信息并发送到信息队列
exit(-1);
}
pid2 = fork(); //创建选手2
if (pid2 == 0)
{
srand((unsigned)time(NULL)*i ); //以时间为种子
result_send(msgid2); //生成选手2的出拳信息并发送到信息队列
exit(-1);
}
if (pid1 < 0 || pid2 < 0)
{
fprintf(stderr, "Fork Failed");
exit(-1);
}
else
{
wait(NULL);
wait(NULL);
struct Game game1;
struct Game game2;
//printf("wait ok.\n");
//从消息队列中取得选手1的出拳信息
msgrcv(msgid1, &game1, sizeof(game1) - sizeof(long), 0, 0);
//printf("rcv1 ok.\n");
//从消息队列中取得选手2的出拳信息
msgrcv(msgid2, &game2, sizeof(game2) - sizeof(long), 0, 0);
//评判出拳结果
//printf("rcv2 ok.\n");
int j = result_announce(game1.Round, game2.Round);
//result_list[i] = result_announce(game1.Round, game2.Round);
result_list[i] = j;
}
}
//printf("end ok.\n");
//将比赛结果写入文件
writeFile(result_list, times);
//删除消息队列
if (msgctl(msgid1, IPC_RMID, 0) == -1)
{
fprintf(stderr, "msgctl(IPC_RMID) failed\n");
}
if (msgctl(msgid2, IPC_RMID, 0) == -1)
{
fprintf(stderr, "msgctl(IPC_RMID) failed\n");
}
exit(EXIT_SUCCESS);}