1、编写C程序,使用Linux中的IPC机制,完成 “石头、剪子、布”的游戏。
决定写这篇是因为在网上都搜不到第二部分的实验内容,自己学会了之后决定写了这个实验的流程
第一部分使用的msgp代码,放了些其他类型的代码可以参考
msgq代码:
#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 //游戏信息
{
long Type;
int Round;
};
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);
}
pipe代码:
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<time.h>
#define MAX_DATA_LEN 256
#define DELAY_TIME 1
/*
数据结构
0:石头
1:剪刀
2:布*/
/*judge函数返回值含义
1:甲赢
0:平局
-1:乙赢*/
int judge(char a,char b) //胜负判定函数
{
if(a==b)
return 0;
else
{
if(a=='0'&&b =='1')
return 1;
if(a=='0'&&b =='2')
return -1;
if(a=='1'&&b =='2')
return 1;
if(a=='1'&&b =='0')
return -1;
if(a=='2'&&b =='0')
return 1;
if(a=='2'&&b =='1')
return -1;
}
}
int main()
{
/*创建第一个管道和第一个子进程*/
pid_t pid;
int pipe_fd[2];
char buf[MAX_DATA_LEN];
char data[20];
int real_read, real_write; //管道的读写操作
memset((void*)buf, 0, sizeof(buf)); //清空缓冲区
if (pipe(pipe_fd) < 0) //判断管道是否创建成功
{
printf("pipe create error\n");
exit(1);
}
if ((pid = fork()) == 0) //创建第一个子进程
{
close(pipe_fd[0]); // 子进程关闭读描述符
sleep(3); //通过使子进程暂停3s等待父进程已关闭相应的写描述符
//子进程在管道中写内容
srand(time(NULL));
int i;
for(i = 0;i<120;i++)
{
sprintf(data,"%d",rand()%3);//随机产生0-2的数字写入管道
while(write(pipe_fd[1],data,strlen(data))==-1);//不断尝试写直到成功
}
close(pipe_fd[1]);
exit(0);
}
/*创建第二个管道和第二个子进程*/
pid_t pid_1;
int pipe_fd_1[2];
char buf_1[MAX_DATA_LEN];
char data_1[20];
int real_read_1, real_write_1;
memset((void*)buf, 0, sizeof(buf)); //清空缓冲区
if (pipe(pipe_fd_1) < 0) //判断管道是否创建成功
{
printf("pipe create error\n");
exit(1);
}
if ((pid_1 = fork()) == 0) //创建第一个子进程
{
close(pipe_fd_1[0]); // 子进程关闭读描述符
sleep(3); //通过使子进程暂停3s等待父进程已关闭相应的写描述符
//子进程在管道中写内容
srand(time(NULL)+120);
int i;
for(i = 0;i<120;i++)
{
sprintf(data_1,"%d",rand()%3);//随机产生0-2的数字写入管道
while(write(pipe_fd_1[1],data_1,strlen(data_1))==-1);//不断尝试写直到成功
}
close(pipe_fd_1[1]); //关闭子进程写描述符
exit(0);
}
/*父进程*/
else if (pid > 0)
{
/* 读取第一个管道的数据 */
close(pipe_fd[1]); //父进程关闭写描述符
sleep(1); //通过使父进程暂停1s等待子进程关闭相应的读描述符
if((real_read = read(pipe_fd[0], buf, MAX_DATA_LEN)) > 0)
{
printf("读取选手甲数据成功!\n");
}
close(pipe_fd[0]); //关闭父进程读描述符
waitpid(pid, NULL, 0); //收集子进程1退出信息
/* 读取第二个管道的数据 */
close(pipe_fd_1[1]); //父进程关闭写描述符
sleep(1); //通过使父进程暂停1s等待子进程关闭相应的读描述符
if((real_read_1 = read(pipe_fd_1[0], buf_1, MAX_DATA_LEN)) > 0)
{
printf("读取选手乙数据成功!\n\n");
}
close(pipe_fd_1[0]); //关闭父进程读描述符
waitpid(pid_1, NULL, 0); //收集子进程2退出信息
/*结束*/
//判定比赛并公示结果
int aw = 0,bw = 0,n_w = 0;
int res = 0;
int i;
for(i = 0;i<120;i++){
printf("第%d回合:",i+1);
res = judge(buf[i],buf_1[i]);
if(res == 1){
printf("甲赢!\n");
aw++;
}
else if(res == -1){
printf("乙赢!\n");
bw++;
}
else{
printf("平局!\n");
n_w++;
}
}
printf("\n比赛结果公示\n");
printf("选手甲赢了:%d次\n",aw);
printf("选手乙赢了:%d次\n",bw);
printf("平局:%d次\n",n_w);
exit(0);
}
return 0;
}
shm代码:
a:
#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<string.h>
#include<time.h>
#include<sys/sem.h>
typedef struct _test{
int a_val;
int b_val;
int a_flag;
int b_flag;
int game_no;
int stage;
}test;
void sem_p();
void sem_v();
void set_sem();
void del_sem();
int sem_id;
union semun{
int val;
struct semid_ds *buf;
unsigned short *arry;
};
int pk[3][3] = {0,-1,1,1,0,-1,-1,1,0};
int other[3][3] = {0,2,1,1,0,2,2,1,0};
int you;
int arr[3];
int main(){
srand((int)time(0));
int shmid;
test* shm;
shmid = shmget((key_t)1236,sizeof(test),0666);
if(shmid == -1){
printf("shmget failed\n");
exit(EXIT_FAILURE);
}
printf("%d",shmid);
shm = shmat(shmid,0,0);
if (shm == (void*)-1){
printf("shmat failed\n");
exit(EXIT_FAILURE);
}
printf("\nMemory attached at %X\n",(int)shm);
sem_id = semget((key_t)3000,1,0666|IPC_CREAT);
int no=0;
while(1){
sem_p();
if(shm->game_no==-1){
sem_v();
break;
}
if (shm->stage==0){
if(no!=shm->game_no){
no = shm->game_no;
printf("-------------------\n");
printf("game_no:%d\n",no);
}
if(shm->a_flag==0){
shm->a_flag=1;
shm->a_val = rand()%3;
printf("you:%d\n",shm->a_val);
you = shm->a_val;
}
}
else if(shm->stage==1){
}
else if(shm->stage==2){
if(shm->a_flag==0){
shm->a_flag=1;
int val=shm->a_val;
printf("other:%d\n",other[you][(val==-1)?2:val]);
if(val==0) {arr[0]++; printf("draw!\n");}
if(val==1) {arr[1]++; printf("you win!\n");}
if(val==-1){arr[2]++; printf("you lost!\n");}
printf("-------------------\n");
}
}
sem_v();
}
printf("draw:%d\nwin:%d\nlost:%d\n",arr[0],arr[1],arr[2]);
shmdt(shm);
}
void set_sem(){
union semun sem_union;
sem_union.val=1;
semctl(sem_id,0,SETVAL,sem_union);
}
void del_sem(){
union semun sem_union;
semctl(sem_id,0,IPC_RMID,sem_union);
}
void sem_p(){
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1;
sem_b.sem_flg = SEM_UNDO;
semop(sem_id,&sem_b,1);
}
void sem_v(){
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1;
sem_b.sem_flg = SEM_UNDO;
semop(sem_id,&sem_b,1);
}
b:
#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<string.h>
#include<time.h>
#include<sys/sem.h>
typedef struct _test{
int a_val;
int b_val;
int a_flag;
int b_flag;
int game_no;
int stage;
}test;
void sem_p();
void sem_v();
void set_sem();
void del_sem();
int sem_id;
union semun{
int val;
struct semid_ds *buf;
unsigned short *arry;
};
int pk[3][3] = {0,-1,1,1,0,-1,-1,1,0};
int other[3][3] = {0,2,1,1,0,2,2,1,0};
int you;
int arr[3];
int main(){
srand((int)time(0));
int shmid;
test* shm;
shmid = shmget((key_t)1236,sizeof(test),0666);
if(shmid == -1){
printf("shmget failed\n");
exit(EXIT_FAILURE);
}
printf("%d",shmid);
shm = shmat(shmid,0,0);
if (shm == (void*)-1){
printf("shmat failed\n");
exit(EXIT_FAILURE);
}
printf("\nMemory attached at %X\n",(int)shm);
sem_id = semget((key_t)3000,1,0666|IPC_CREAT);
int no=0;
while(1){
sem_p();
if(shm->game_no==-1){
sem_v();
break;
}
if (shm->stage==0){
if(no!=shm->game_no){
no = shm->game_no;
printf("-------------------\n");
printf("game_no:%d\n",no);
}
if(shm->b_flag==0){
shm->b_flag=1;
shm->b_val = rand()%3;
printf("you:%d\n",shm->b_val);
you = shm->b_val;
}
}
else if(shm->stage==1){
}
else if(shm->stage==2){
if(shm->b_flag==0){
shm->b_flag=1;
int val=shm->b_val;
printf("other:%d\n",other[you][(val==-1)?2:val]);
if(val==0) {arr[0]++; printf("draw!\n");}
if(val==1) {arr[1]++; printf("you win!\n");}
if(val==-1){arr[2]++; printf("you lost!\n");}
printf("-------------------\n");
}
}
sem_v();
}
printf("draw:%d\nwin:%d\nlost:%d\n",arr[0],arr[1],arr[2]);
shmdt(shm);
}
void set_sem(){
union semun sem_union;
sem_union.val=1;
semctl(sem_id,0,SETVAL,sem_union);
}
void del_sem(){
union semun sem_union;
semctl(sem_id,0,IPC_RMID,sem_union);
}
void sem_p(){
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1;
sem_b.sem_flg = SEM_UNDO;
semop(sem_id,&sem_b,1);
}
void sem_v(){
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1;
sem_b.sem_flg = SEM_UNDO;
semop(sem_id,&sem_b,1);
}
test:
#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/sem.h>
#include<string.h>
typedef struct _test{
int a_val;
int b_val;
int a_flag;
int b_flag;
int game_no;
int stage;
}test;
int pk[3][3] = {0,-1,1,1,0,-1,-1,1,0};
void sem_p();
void sem_v();
void set_sem();
void del_sem();
int sem_id;
union semun{
int val;
struct semid_ds *buf;
unsigned short *arry;
};
int main(){
int shmid;
test* shm;
shmid = shmget((key_t)1236,sizeof(test),0666|IPC_CREAT);
if(shmid == -1){
printf("shmget failed\n");
exit(EXIT_FAILURE);
}
printf("%d",shmid);
shm = shmat(shmid,0,0);
if (shm == (void*)-1){
printf("shmat failed\n");
exit(EXIT_FAILURE);
}
printf("\nMemory attached at %X\n",(int)shm);
sem_id = semget((key_t)3000,1,0666|IPC_CREAT);
set_sem();
int no=0,debug=0,a,b;
shm->a_flag=0; shm->a_val = -2;
shm->b_flag=0; shm->b_val = -2;
shm->game_no=1;
shm->stage=0;
while(1){
sem_p();
//printf("a:%d b:%d\n",shm->a_val,shm->b_val); sleep(1);
if(shm->game_no==-1){
sem_v();
break;
}
if (shm->stage==0){
if(no!=shm->game_no){
no = shm->game_no;
printf("-------------------\n");
printf("game_no:%d\n",no);
}
if(shm->a_flag==1 && shm->b_flag==1) shm->stage=1;
}
else if(shm->stage==1){
printf("a:%d\n",shm->a_val);
printf("b:%d\n",shm->b_val);
a = pk[shm->a_val][shm->b_val];
b = pk[shm->b_val][shm->a_val];
shm->a_val=a;
shm->b_val=b;
shm->a_flag=0;
shm->b_flag=0;
shm->stage=2;
}
else if(shm->stage==2){
if(shm->a_flag==1 && shm->b_flag==1){
shm->stage=0;
shm->game_no++;
shm->a_flag=0;
shm->b_flag=0;
printf("-------------------\n");
if(shm->game_no > 100) shm->game_no=-1;
}
}
sem_v();
}
shmdt(shm);
int ret=0;
ret = shmctl(shmid,IPC_RMID,NULL);
if(ret<0){
printf("shmctl error!\n");
}
del_sem();
printf("finish");
}
void set_sem(){
union semun sem_union;
sem_union.val=1;
semctl(sem_id,0,SETVAL,sem_union);
}
void del_sem(){
union semun sem_union;
semctl(sem_id,0,IPC_RMID,sem_union);
}
void sem_p(){
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1;
sem_b.sem_flg = SEM_UNDO;
semop(sem_id,&sem_b,1);
}
void sem_v(){
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1;
sem_b.sem_flg = SEM_UNDO;
semop(sem_id,&sem_b,1);
}
socket代码:
选手1:
#include<stdlib.h>
#include<time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
int main()
{
int sockfd1 =-1;
char game1;
int len = 0;
struct sockaddr_in address;
int result;
char ch='A';
srand((unsigned)time(NULL));
sockfd1 = socket(AF_INET, SOCK_STREAM, 0);
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("127.0.0.1");
address.sin_port = htons(9736);
len = sizeof(address);
result = connect(sockfd1, (struct sockaddr*)&address, len);
if(result == -1)
{
perror("ops:client\n");
exit(1);
}
for (int i=0;i<=100;i++){
game1=rand()%3+'0';
write(sockfd1, &game1, 1);
read(sockfd1, &ch, 1);
printf("result form server = %c\n",ch);
printf("game1 form server = %c\n",game1);}
close(sockfd1);
exit(0);
}
选手2:
#include<stdlib.h>
#include<time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
int main()
{
int sockfd2 =-1;
char game2;
int len = 0;
char ch='A';
struct sockaddr_in address;
int result;
srand((unsigned)time(NULL));
sockfd2 = socket(AF_INET, SOCK_STREAM, 0);
address.sin_family = AF_INET;//使用网络套接字
address.sin_addr.s_addr = inet_addr("127.0.0.1");//服务器地址
address.sin_port = htons(9736);//服务器所监听的端口
len = sizeof(address);
result = connect(sockfd2, (struct sockaddr*)&address, len);
if(result == -1)
{
perror("ops:client\n");
exit(1);
}
for (int i=0;i<=100;i++){
game2=rand()%3+'0';
write(sockfd2, &game2, 1);
//从服务器获取数据
read(sockfd2, &ch, 1);
printf("result form server = %c\n", ch);
printf("game2 form server = %c\n", game2);}
close(sockfd2);
exit(0);
}
裁判:
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<signal.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int server_sockfd = -1;
int client_sockfd1 = -1;
int client_sockfd2= -1;
int client_len1 = 0;
int client_len2 = 0;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr1;
struct sockaddr_in client_addr2;
char game1;
char game2;
int count=0;
int result;
char ch='H';
server_sockfd = socket(AF_INET,SOCK_STREAM,0);
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(9736);
bind(server_sockfd,(struct sockaddr*)&server_addr,sizeof(server_addr));
listen(server_sockfd, 100);
signal(SIGCHLD, SIG_IGN);
client_len1= sizeof(client_addr1);
client_len2= sizeof(client_addr2);
printf("Server waiting\n");
client_sockfd1 =accept(server_sockfd,(struct sockaddr*)&client_addr1,&client_len1);
client_sockfd2 =accept(server_sockfd,(struct sockaddr*)&client_addr2,&client_len2);
for(int i=0;i<=100;i++)
{
read(client_sockfd2,&game2,1);
read(client_sockfd1,&game1,1);
sleep(3);
if(game1==game2)
{
ch='D';
}
if( (game1=='2'&&game2=='1')||(game1=='1'&&game2=='0')||(game1=='0'&&game2=='2'))
{
ch='W';
}
if((game2=='2'&&game1=='1')||(game2=='1'&&game1=='0')||(game2=='0'&&game1=='2'))
{
ch='L';
}
printf("game1:%c\n",game1);
printf("game2:%c\n",game2);
printf("%c\n",ch);
write(client_sockfd1,&ch,1);
write(client_sockfd2,&ch,1);
} close(client_sockfd1);
close(client_sockfd2);
exit(0);
/*else
{
/*close(client_sockfd1);
close(client_sockfd2);
}*/
}
实验结果:
2、修改上述程序,使之能够在网络上运行该游戏。
这部分使用的代码是上面的socket代码,不再复制了
提示:要将代码中的端口和ip换成自己的,如何在控制台搜索能用的ip和端口自己去搜。
运行时要将裁判的代码先运行,出现server waiting说明是正确的,再重新打开控制台打开选手1的,再重新打开一个打开选手2的,等待一会就会出现结果