linux进程间通信实现剪刀石头布 您所在的位置:网站首页 一个石头子 linux进程间通信实现剪刀石头布

linux进程间通信实现剪刀石头布

2024-07-01 07:14| 来源: 网络整理| 查看: 265

linux进程间通信实现剪刀石头布-命名管道 为何要写这篇文章?

因为本人在操作课程上需要写这么个东西,查阅网络资料,发现似乎只有一个源码! 全网就那么一个源码,抄都没得抄。 https://blog.csdn.net/weixin_33672109/article/details/94240244 连接放在这里。 这段代码没有问题,可以正常运行,但可惜的是,他是一次性生成了100个随机数塞进管道里,随后再由裁判统一判定,这样显然不是真实的猜拳流程,人不可能虚空划拳。 老师也要求程序应当有“轮”的概念,在本人捣鼓了半晚上之后,终于凑合捏了个东西出来造福人类。(反正我已经打完分了233)

linux进程间通信的方案那么多,你用的是啥?

FIFO/命名管道 为啥,因为简单呗

正文

首先我在google上找到了一个FIFO通信的原型,这货允许两个进程间互相发送信息

https://www.geeksforgeeks.org/named-pipe-fifo-example-c-program/

还要啥自行车,在他的基础上改改呗~

judger.c

#include #include #include #include #include #include #include int judge(char a,char b)//判定规则 { int r=0; if(a==b) r=0; else { if(a=='0'&&b=='1')r=1; if(a=='0'&&b=='2')r=-1; if(a=='1'&&b=='2')r=1; if(a=='1'&&b=='0')r=-1; if(a=='2'&&b=='0')r=1; if(a=='2'&&b=='1')r=-1; } return r; } int main() { int fd1,fd2,fd3,fd4; // FIFO file path char * myfifo1 = "/tmp/myfifo1"; char * myfifo2 = "/tmp/myfifo2"; char * myfifo3 = "/tmp/myfifo3"; char * myfifo4 = "/tmp/myfifo4"; // Creating the named file mkfifo(myfifo1, 0666); mkfifo(myfifo2, 0666); mkfifo(myfifo3, 0666); mkfifo(myfifo4, 0666); char arr1[1],arr2[1]; char start[1] = {'5'}; char end[1] = {'7'}; printf("i'm judger!\n"); int l = 0; int draw=0; int pw1=0; int pw2=0; while (1) { l++; if(l>100){ //end fd1 = open(myfifo1, O_WRONLY); fd2 = open(myfifo2, O_WRONLY); write(fd1, end, strlen(start)+1); write(fd2, end, strlen(start)+1); close(fd1); close(fd2); break; } printf("---------this is the %d loop---------\n",l); // Open write only fd1 = open(myfifo1, O_WRONLY); fd2 = open(myfifo2, O_WRONLY); // Write // and close write(fd1, start, strlen(start)+1); write(fd2, start, strlen(start)+1); //start !! close(fd1); close(fd2); usleep(10); // Open Read only fd3 = open(myfifo3, O_RDONLY); fd4 = open(myfifo4, O_RDONLY); // Read from FIFO read(fd3, arr1, sizeof(arr1)); read(fd4, arr2, sizeof(arr2)); printf("player1: %c\n", arr1[0]); printf("player2: %c\n", arr2[0]); close(fd3); close(fd4); int tmp = judge(arr1[0],arr2[0]); if(tmp==0) { printf("in a draw!\n");//平局 draw++; } else { printf("%s wins!\n",(tmp>0)?"p1":"p2"); if(tmp>0){ pw1++;}else{ pw2++;} } } printf("--------------\nsummary:\nthe draw:%d\nplayer1 win:%d\nplayer2 win:%d\n--------------\n",draw,pw1,pw2); return 0; }

player1.c

#include #include #include #include #include #include #include #include int main() { int fd1,fd3; // FIFO file path char * myfifo1 = "/tmp/myfifo1"; char * myfifo3 = "/tmp/myfifo3"; mkfifo(myfifo1, 0666); mkfifo(myfifo3, 0666); char str1[1]; int l = 0; srand(time(NULL)); while (1) { usleep(5); l++; printf("---------this is the %d loop---------\n",l); fd1 = open(myfifo1,O_RDONLY); read(fd1, str1, 1); printf("judge: %c --> ", str1[0]); close(fd1); if(str1[0] == '5'){ fd3 = open(myfifo3,O_WRONLY); int j = rand()%3; str1[0] = j + '0'; write(fd3, str1, strlen(str1)+1); printf("dict=%d\n",j); close(fd3); }else if(str1[0] == '7'){ printf("exit\n"); break; } } return 0; }

player2.c

#include #include #include #include #include #include #include #include int main() { int fd2,fd4; // FIFO file path char * myfifo2 = "/tmp/myfifo2"; char * myfifo4 = "/tmp/myfifo4"; mkfifo(myfifo2, 0666); mkfifo(myfifo4, 0666); char str2[1]; srand((unsigned)(time(NULL)+100)); int l=0 ; while (1) { usleep(10); l++; printf("---------this is the %d loop---------\n",l); fd2 = open(myfifo2,O_RDONLY); read(fd2, str2, 1); printf("judge: %c --> ", str2[0]); close(fd2); if(str2[0] == '5'){ fd4 = open(myfifo4,O_WRONLY); int j = rand()%3; str2[0] = j + '0'; write(fd4, str2, strlen(str2)+1); printf("dict=%d\n",j); close(fd4); }else if(str2[0] == '7'){ printf("exit\n"); break; } } return 0; }

ok,到此,功能就可以实现了。 两个player完全可以使用fork()合并在同一个文件里,但由于一晚上时间紧迫,本人又没学过c,故放弃。

一些坑

c语言随机数使用srand(time(NULL))来定义种子,时间精确到秒,所以可能会发生seed相同的情况,故不同进程的srand请 + 一个数字,区分开来。

srand在循环外侧使用一次即可!!!千万别放在循环里面,每次重新初始化会导致大量重复值

rand()返回值为int,需要转换为char rand()%3 + '0' 注意是单引号。 char使用printf()的%d打印可能会出现一些奇怪的乱码,请用%c

sleep()函数在win下单位是毫秒 linux下是秒,1s太久,我们只争朝夕啊,所以用usleep() 不过FIFO管道似乎会自动阻塞,所以其实不需要延迟的 我仍不知道管道自己会不会自动清空,但看起来应该是会的,在read之后,管道里啥都木得了。

运行时请打开三个终端一起运行鸭

在这里插入图片描述 哦 这基佬紫色的终端~

事情到这里应该就结束了,不过我的室友看到我在这里写文章,他也想投入到这造福人类的伟大事业之中来,因此再提供一个版本的代码

使用fork()的版本 #include #include #include #include #include #include #include #include #include #include int judge(char a,char b); int main(void) { int fd1,fd2,fd3,fd4,i=0; int status; char * myfifo1 = "/tmp/myfifo1"; char * myfifo2 = "/tmp/myfifo2"; char * myfifo3 = "/tmp/myfifo3"; char * myfifo4 = "/tmp/myfifo4"; char start[1] = {'3'}; char end[1] = {'4'}; char c1[1];//用来存放p1发送的消息 char c2[2];//用来存放p2发送的消息 char s1[1];//用来存放裁判发送的消息 char s2[2];//用来存放裁判发送的消息 int p1w=0,p2w=0,pd=0; /**************************************/ //创建4个管道 if((mkfifo(myfifo1,0666) printf("cannot create fifo.\n"); exit(1); } if((mkfifo(myfifo3,0666) printf("cannot create fifo.\n"); exit(1); } /*********************************/ //产生子进程p1 pid_t p1 = fork(); /*********************************/ if(p1==0) { srand(time(NULL)); while(1) { i++; fd1 = open(myfifo1,O_RDONLY); read(fd1,s1,1); close(fd1); if(s1[0] == '3') { fd3 = open(myfifo3,O_WRONLY); int j = rand()%3; s1[0] = j + '0'; write(fd3,s1,strlen(s1)+1); close(fd3); }else if(s1[0] == '4'){ exit(0); } } return 0; } /*********************************/ //产生子进程p2,程序结构同p1 pid_t p2=fork(); /*********************************/ if(p2==0) { srand(time(NULL)+100); while(1) { i++; fd2 = open(myfifo2,O_RDONLY); read(fd2,s2,1); close(fd2); if(s2[0] == '3') { fd4 = open(myfifo4,O_WRONLY); int j = rand()%3; s2[0] = j + '0'; write(fd4,s2,strlen(s2)+1); close(fd4); }else if(s2[0] == '4'){ exit(0); } } return 0; } //比赛场地 while(1) { if(p1 != 0 && p2!=0){ i++; if(i>100) { fd1 = open(myfifo1,O_WRONLY); fd2 = open(myfifo2,O_WRONLY); write(fd1,end,strlen(start)+1); write(fd2,end,strlen(start)+1); close(fd1); close(fd2); break; } printf("这是第 %d 轮\n",i); //只写打开命名管道1,2 fd1 = open(myfifo1,O_WRONLY); fd2 = open(myfifo2,O_WRONLY); //向管道1,2中写入开始出拳信号start write(fd1,start,strlen(start+1)); write(fd2,start,strlen(start+1)); close(fd1); close(fd2); sleep(1); //只读打开命名管道3,4 fd3 = open(myfifo3,O_RDONLY); fd4 = open(myfifo4,O_RDONLY); //从管道3,4中读出比赛选手出拳情况 read(fd3,c1,sizeof(c1)); read(fd4,c2,sizeof(c2)); //打印一轮结果 printf("p1: %c\n",c1[0]); printf("p2: %c\n",c2[0]); close(fd3); close(fd4); int tmp = judge(c1[0],c2[0]); if(tmp==0) { printf("in a draw!\n"); pd++;//平局 } else { printf("%s wins!\n",(tmp>0)?"p1":"p2"); if(tmp>0){ p1w++;//p1胜 } else { p2w++; //p2胜 } } } } //打印最终统计结果 printf("In summary:\n"); printf("p1 wins %d rounds.\n",p1w); printf("p2 wins %d rounds.\n",p2w); printf("%d rounds end in a draw.\n",pd); printf("%s wins in the game!\n",(p1w>p2w)?"p1":"p2"); } //0——石头,1——剪刀,2——布 int judge(char a,char b)//规定游戏判定规则 { int r=0; if(a==b){ r=0;} else { if(a=='0'&&b=='1')r=1; if(a=='0'&&b=='2')r=-1; if(a=='1'&&b=='2')r=1; if(a=='1'&&b=='0')r=-1; if(a=='2'&&b=='0')r=1; if(a=='2'&&b=='1')r=-1; } return r; }

在这里插入图片描述

不过有个缺点,就是每秒才能生成一轮,虽然不知道他具体在哪里出了点小问题,总之我也懒得管了,你们自己看着去改吧。

就酱 溜了溜了



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有