Linux下有名管道实现的猜数字小游戏(C语言)

作者的废话:Linux课程设计要求使用符合Linux特性来写一个小代码,只要求在终端上运行,看表格上好多同学不是写关于命令的,就是文件的复制操作之类的,还有一大半的聊天系统,我实现想不出来要写什么,就随便报了个使用管道通信的三端(一个服务端,两个客户端)猜数字小游戏,有趣的是我们老师还说这个在网上有很多,后来想看看(抄袭X)别人怎么写的,结果在CSDN和GitHub上都没找到类似的,最后自己写了个初始的(还有一堆bug的,别问,问就是Linux课上在学其他东西,嘤嘤嘤),后面哪怕去找AI都解决不了(GPT3.5是真的无语辣),最后还是去请教舍友后才把bug解决了(bug主要是因为管道少了,造成两客户端和服务端相互竞争,缓冲区相互读写覆盖了)。

运行效果:

首先运行服务器端的代码,再运行两个客户端的代码,当一个客户端猜测的时候,另一个可不能偷跑哦~所以输不了数字,只能轮流输入。服务器端会对猜测的数字进行判断,而两个客户端也会给出更新的数字区间进行提示。

至于代码的讲解,我写了非常~非常详细的注释哦~

代码如下:

服务器端代码

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<time.h>
#include<string.h>

//宏定义三个管道
#define PLAYER1_PIPE "player1_pipe"
#define PLAYER2_PIPE "player2_pipe"
#define PLAYER3_PIPE "player3_pipe"

//服务器
int main(){
    //管道文件1、2、3
    int player1_fd, player2_fd,player3_fd;

    int min_number = 1; //数字区间下界
    int max_number = 100; //数字区间上界

    int secret_number; //秘密数字
    char buffer[10]; //缓冲区

    //以时间戳生成秘密数字(1-100)
    srand(time(NULL));
    secret_number = rand() % 100 + 1;

    printf("秘密数字: %d\n", secret_number);

    //创建命名管道
    mkfifo(PLAYER1_PIPE, 0666);
    mkfifo(PLAYER2_PIPE, 0666);
    mkfifo(PLAYER3_PIPE, 0666);

    //打开管道
    player1_fd = open(PLAYER1_PIPE, O_RDWR);
    player2_fd = open(PLAYER2_PIPE, O_RDWR);
    player3_fd = open(PLAYER3_PIPE, O_RDWR);

    while(1)
    {//当有玩家猜对数字时结束循环,既game over~
	//向玩家1发送当前的数字范围
        sprintf(buffer, "%d-%d", min_number, max_number);
        write(player1_fd, buffer, sizeof(buffer)); //写入缓冲区

	//从管道3中读取玩家1的猜测
        read(player3_fd, buffer, sizeof(buffer));
        int player3_guess = atoi(buffer); //将字符串buffer转换为整数

	//对玩家1的猜测进行判断
        if(player3_guess == secret_number)
	{
            printf("玩家1获胜!\n");
	    sprintf( buffer,"%s","e");
	    //玩家1猜对数字,服务器发送代表玩家1获胜的字符e给管道1和2
	    write(player1_fd, buffer, sizeof(buffer));
	    write(player2_fd, buffer, sizeof(buffer));

            break;
        }else if(player3_guess > secret_number && player3_guess < max_number){//更新上界
            printf("玩家1猜测的数字太大辣~\n");
            max_number = player3_guess - 1;

        }else if(player3_guess < secret_number && player3_guess > min_number){//更新下界
            printf("玩家1猜测的数字太小辣~\n");
            min_number = player3_guess + 1;

        }else if(player3_guess > max_number){
            printf("数字超过区间上界了哦~");

        }else if(player3_guess < min_number){
            printf("数字超过区间下界了哦~");

        }

	//把数字区间上界和下界转换成字符串存储到缓冲区buffer中
        sprintf(buffer, "%d-%d", min_number, max_number);
        write(player2_fd, buffer, sizeof(buffer)); //发送给玩家2

	//从管道3中读取玩家2的猜测
        read(player3_fd, buffer, sizeof(buffer));
        player3_guess = atoi(buffer); //转回数字

	//判断玩家2的猜测
        if(player3_guess == secret_number)
	{
            printf("玩家2获胜!\n");
	    sprintf( buffer,"%s","f");
	    //玩家2猜对数字,服务器发送代表玩家2获胜的字符e给管道1和2
            write(player2_fd, buffer, sizeof(buffer));
	    write(player1_fd, buffer, sizeof(buffer));

            break;
        }else if(player3_guess > secret_number && player3_guess < max_number){ //更新上界
            printf("玩家2猜测的数太大辣~\n");
            max_number = player3_guess - 1;

        }else if(player3_guess < secret_number && player3_guess > min_number){ //更新下界
            printf("玩家2猜测的数字太小辣~\n");
            min_number = player3_guess + 1;

        }else if(player3_guess > max_number){
            printf("数字超过区间上界了哦~");

        }else if(player3_guess < min_number){
            printf("数字超过区间下界了哦~");

        }

    }

    //关闭三个管道,释放资源
    close(player1_fd);
    close(player2_fd);
    close(player3_fd);

    //删除三个管道
    unlink(PLAYER1_PIPE);
    unlink(PLAYER2_PIPE);
    unlink(PLAYER3_PIPE);

    return 0;
}

客户端1的代码:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>

#define PLAYER1_PIPE "player1_pipe"
#define PLAYER3_PIPE "player3_pipe"

//玩家1端
int main(){
    //打开两个管道,可读写模式
    int player1_fd = open(PLAYER1_PIPE, O_RDWR);
    int player3_fd = open(PLAYER3_PIPE, O_RDWR);

    char buffer[10];

    while(1)
    {
	//从管道1中读取数据
        ssize_t bytes_read = read(player1_fd, buffer, sizeof(buffer));

	//缓冲区中有数据才会进入判断,当缓冲区没有数据时配合usleep挂起,以达成轮流输入
	//当玩家1输入时,玩家2不能输入,陷入死等,只有等玩家1输入完后玩家2才可以输入
        if(bytes_read > 0)
	{
	    if(buffer[0] == 'e')
	    {
		printf("Victory!\n");
               	break;

            }else if(buffer[0] == 'f'){
		printf("Defeat!\n");
		break;

	    }

            printf("猜测数字区间: %s\n", buffer);

            int min_number, max_number;
            sscanf(buffer, "%d-%d", &min_number, &max_number); //从字符串中解析出两个数字,提示玩家1猜数区间

	    //输入玩家1的猜测
            int guess;
            printf("玩家1,请输入你的猜测: ");
            scanf("%d", &guess);

            sprintf(buffer, "%d", guess); //转换成字符串
            
	    //写入管道3中
            write(player3_fd, buffer, sizeof(buffer));

        }else if(bytes_read == 0){
	    //提示玩家2退出游戏
            printf("玩家2跑路辣!\n");
            break;

        }else if(errno != EAGAIN && errno != EWOULDBLOCK){
	    //非阻塞I/O操作错误,资源不可用,比如当管道不存在时报个错~
            perror("read error");
            break;  

        }

	//暂停执行一毫秒,避免忙等
        usleep(1000);
    }

    //关闭管道1和3
    close(player1_fd);
    close(player3_fd);

    return 0;
}

客户端2的代码:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>

#define PLAYER2_PIPE "player2_pipe"
#define PLAYER3_PIPE "player3_pipe"

//玩家2端
int main(){
    //打开管道2和3
    int player2_fd = open(PLAYER2_PIPE, O_RDWR);
    int player3_fd = open(PLAYER3_PIPE, O_RDWR);

    char buffer[10];

    while(1)
    {
	//从管道2中读取数据
        ssize_t bytes_read = read(player2_fd, buffer, sizeof(buffer));
        if(bytes_read > 0)
	{
	    if(buffer[0] == 'f')
	    {
                printf("Victory!\n");
                break;
            }else if(buffer[0] == 'e'){
		printf("Defeat!\n");
		break;
	    }
            printf("猜测数字区间: %s\n", buffer);

	    //给出数字区间上下界
            int min_number, max_number;
            sscanf(buffer, "%d-%d", &min_number, &max_number);

            int guess;
            printf("玩家2,请输入你的猜测: ");
            scanf("%d", &guess); //玩家2输入猜测

	    //写入管道3中
            sprintf(buffer, "%d", guess);
            write(player3_fd, buffer, sizeof(buffer));
	    
        }else if(bytes_read == 0){
	    //提示玩家1退出游戏
            printf("玩家1跑路辣!\n");
            break;  
        }else if(errno != EAGAIN && errno != EWOULDBLOCK){
	    //非阻塞I/O操作错误,同玩家1
            perror("read error");
            break;  
        }

	//挂起
        usleep(1000);
    }

    //关闭管道2和3
    close(player2_fd);
    close(player3_fd);

    return 0;
}

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值