基于c语言实现的TCP连网斗地主程序(一)

前言:本程序涉及递归,冒泡排序,结构体,网络,IO多路复用,线程等知识,读者如果此方面的基础,请先学习后再来阅读。

温馨提示:本文中有些判断函数中有大量的else if()语句,注意,这不是写错了,也不是上传错了,更不是网页加载错误,这是本程序中存在的。拿judge_airplane_20举例,它是用来判断玩家出牌二十张的合法性,本程序是采用将9之后的牌,从小到大替换为字母,这样方便于判断出牌的大小合法性。二十张牌的飞机可能是五个连着的三带一,也可能是四个连着的三带二,同时由于9与10(为了方便,我将10替换为了T给用户打印,本程序在程序计算时将10替换为了a,当判断玩家牌合法后,又将牌替换为T)之间相当于ASCII码中的57和97,我们无法预知9和10在什么位置,同时五个三带一也有333444455566677789TJ的情况,这又是一种情况,同样的玩家可能中间有两个四张一样的,三个四张一样的,这种情况虽然出现的机率很小,但是我们还是需要考虑进去的,即使只有万分之一的可能,我们也应该尽可能取避免。 

阐述一下思路:首先客户端登陆,需要先创建name,然后输入start+一个0-3的字符(如start0),然后服务器会将客户端的acceptfd记录在房间信息结构体中,一个房间三个用户,当进来三个用户时,会开始游戏,同时其他人想进入房间会提示房间满。选择这种输入方式,即使后连接的客户端也可以和最先连接的客户端进入到同一个房间中,类似于面对面建群聊。同时要保证多个用户可以同时进行,所以连接时采用IO多路复用的方式接收信息,开始游戏时采用线程。

开始游戏的第一步需要先生成随机的每个用户的牌堆,这里我的初始牌堆就是打乱的,又根据随机生成函数,写了一个随机生成0~53的函数,这里要求每个生成的数不可以重复,采用了递归,同时保证每次的牌不是相同的。同时生成一个0~(54-3)的随机数,这张是地主标志,最后三张是地主牌,然后将牌堆反别发给三个玩家的牌堆,将玩家各自的牌堆发送到他们的客户端,同时告诉所有人谁是地主。

这是要按照谁是地主生成出牌顺序,让用户出牌或过,出是其他的会判断后让重新出,还要判断出牌的合法性,因此这里有大量的判断语句,本文中放不下,放在了下两篇。用户出牌合法后要更新牌信息的标志位,通过判断标志位来决定牌是否正确。一个用户出牌后,其他两个用户出guo,需要更新标志,让这名用户可以继续出任意牌,而不是去和自己出过的牌比较。

循环出牌,每次出牌后将这名用户牌的信息更新后发送给他,还要将他出的牌以及他的身份,剩余的牌数量发送给所有人,判断他是否还有牌,没牌后判断身份后发送给所有用户哪边胜利。

客户端采用父子进程,一个用来发送消息,一个用来接收服务器发来的消息。

修复了客户端同时进入出错的bug,每次出牌时,给当前用户发送他的牌的信息。游戏开始后释放房间资源,其他玩家可以通过这个房间再开始游戏。

提示(编译时要链接pthread)(gcc 文件名 -lpthread)(运行时需要输入./a.out 主机号+端口号)

(如果先关闭服务器,客户端会自动关闭,这时一定要pidof 客户端程序名)通过kill把孤儿进程全部杀死

不然会一直占用!!!!!!!

(有些电脑运行后,地主出牌会推出,可能是虚拟机或者编译器的版本问题,需要修改一下数组的大小)

服务器代码(由于限制文中字数,判断的条件太多,我把判断的代码放在了下一个文中)

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <fcntl.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <dirent.h>
#include <sys/wait.h>
#include <pthread.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <signal.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sqlite3.h>
#define PRINT_ERR(msg) \
    do {               \
        perror(msg);   \
        return -1;     \
    } while (0)
#define ERRLOG(msg) do{\
        printf("%s %s %d:", __FILE__, __func__, __LINE__);\
        perror(msg);\
        exit(-1);\
}while(0)

typedef struct user_msg{
    int acceptfd;
    struct sockaddr_in clientaddr;
}user_msg_t;

typedef struct play{
    char player_brand[30];
    int brands;
    char ID[10];
    char name[20];
    int acceptfd;
}players_t;

typedef struct p_info{
    int acceptfd_0;
    struct sockaddr_in clientaddr_0;
    char name_0[20];
    int acceptfd_1;
    struct sockaddr_in clientaddr_1;
    char name_1[20];
    int acceptfd_2;
    struct sockaddr_in clientaddr_2;
    char name_2[20];
}players_info_t;

typedef struct b_info{
    char double_brands:1;
    char triple:1;
    char triple_and_one:1;
    char triple_and_double:1;
    char strgight:1;
    char airplane:1;
    char strgight_double:1;
    char bomb_and_two:1;
    char brands_num;
    char bomb_and_double;
    char bomb;
    char kings;
    char brands_flag;
}brands_info_t;

players_info_t players_info_0;
players_info_t players_info_1;
players_info_t players_info_2;
players_info_t players_info_3;
fd_set readfds;
void clear_brand(char c_brand[]);
void replace_brand_to_player(char r_brand[],int brands);
void replace_brand_to_computer(char r_brand[],int brands);
int judge_out_brand(char s_now[],players_t* player,players_t* player1,players_t* player2,brands_info_t* brands_info_last,brands_info_t* brands_info);
void refresh_brands(int temp_brands_numb[],char player_brands[],int numbs,int* brands);
int judge_strgight_5(int temp_brands_numb[],char player_brand[]);
int judge_strgight_6(int temp_brands_numb[],char player_brand[]);
int judge_strgight_7(int temp_brands_numb[],char player_brand[]);
int judge_strgight_8(int temp_brands_numb[],char player_brand[]);
int judge_strgight_9(int temp_brands_numb[],char player_brand[]);
int judge_strgight_10(int temp_brands_numb[],char player_brand[]);
int judge_strgight_11(int temp_brands_numb[],char player_brand[]);
int judge_strgight_12(int temp_brands_numb[],char player_brand[]);
int judge_strgight_13(int temp_brands_numb[],char player_brand[]);
int judge_strgight_double_6(int temp_brands_numb[],char player_brand[]);
int judge_strgight_double_8(int temp_brands_numb[],char player_brand[]);
int judge_strgight_double_10(int temp_brands_numb[],char player_brand[]);
int judge_strgight_double_12(int temp_brands_numb[],char player_brand[]);
int judge_strgight_double_14(int temp_brands_numb[],char player_brand[]);
int judge_strgight_double_16(int temp_brands_numb[],char player_brand[]);
int judge_strgight_double_18(int temp_brands_numb[],char player_brand[]);
int judge_strgight_double_20(int temp_brands_numb[],char player_brand[]);
int judge_airplane_6(int temp_brands_numb[],char player_brand[]);
int judge_airplane_8(int temp_brands_numb[],char player_brand[]);
int judge_airplane_9(int temp_brands_numb[],char player_brand[]);
int judge_airplane_10(int temp_brands_numb[],char player_brand[],char *s);
int judge_airplane_12(int temp_brands_numb[],char player_brand[],char* s);
int judge_airplane_15(int temp_brands_numb[],char player_brand[],char* s);
int judge_airplane_16(int temp_brands_numb[],char player_brand[],char* s);
int judge_airplane_18(int temp_brands_numb[],char player_brand[]);
int judge_airplane_20(int temp_brands_numb[],char player_brand[]);
int judge_bomb_and_double_8(int temp_brands_numb[],char player_brand[],char* s);
int creat_room(char room,int acceptfd,struct sockaddr_in clientaddr,char name[]);
int send_all_info(char buff[],players_info_t players_info);
int send_info(char buff[],int acceptfd);
int recv_info(char buff[],int acceptfd);
void show(players_t player);
int judge_win(players_t player1,players_t player2,players_t player3);
int judge_order(int landowner,players_t *player1,players_t *player2,players_t *player3);


/*
参数:players_t *player 当前出牌玩家的信息;
    players_t* player1,players_t* player2 其余两名玩家的信息;
    brands_info_t* brands_info_last,brands_info_t* brands_info 上一次出牌玩家牌的信息和这一次出牌的信息
功能:让玩家出牌
返回值:如果玩家出guo不进入判断牌的函数,不是则进入
*/
int out_brand(players_t *player,players_t* player1,players_t* player2,brands_info_t* brands_info_last,brands_info_t* brands_info){
    static int guo=0;
    if(guo==2){
        memset(brands_info_last,0,sizeof(struct b_info));
    }      
    show(*player);
    memset(brands_info,0,sizeof(struct b_info));
    char buff[128]={0};
    sprintf(buff,"please output brands>");
    send_info(buff,player->acceptfd);
    char s_now[21]={0};
    char text[128]={0};
    recv_info(s_now,player->acceptfd);
    if(!strcmp(s_now,"guo")){
        guo++;
        sprintf(text,"player[%s(%s)(%d)] :%s",player->name,player->ID,player->brands,s_now);
        send_info(text,player->acceptfd);
        send_info(text,player1->acceptfd);
        send_info(text,player2->acceptfd);
        return 0;
    }
    replace_brand_to_computer(s_now,strlen(s_now));
    if(judge_out_brand(s_now,player,player1,player2,brands_info_last,brands_info)){
        show(*player);
        guo=0;
    }
}

/*
参数:char s_now[] 玩家出的牌
    players_t* player 当前出牌玩家的信息
    players_t* player1,players_t* player2 其余两名玩家的信息;
    brands_info_t* brands_info_last,brands_info_t* brands_info 当前出牌的信息以及上一次出牌的信息
功能:判断牌的合法性,对比两次牌信息判断是否合法,不合法调用out_brand;
返回值:出牌错误返回0,out_brand函数根据返回值给玩家发送更新后的牌
*/
int judge_out_brand(char s_now[],players_t* player,players_t* player1,players_t* player2,brands_info_t* brands_info_last,brands_info_t* brands_info){
    int i=0;
    int brand_postion=0;
    int temp_brands_numb[20]={0};
    int brands=player->brands;
    char player_brand[20]={0};
    char error_str_1[30]={0};
    char error_str_2[25]={0};
    char buff[128]={0};
    brands_info_t brands_info_temp;
    memset(&brands_info_temp,0,sizeof(brands_info_temp));
    sprintf(error_str_1,"you don't have the brands!");
    sprintf(error_str_2,"output brands again>");
    strcpy(player_brand,player->player_brand);
    while(s_now[i]){
        for(;brand_postion<brands;){
            if(s_now[i]!=player_brand[brand_postion]){
                brand_postion++;                
                continue;
            }     
            temp_brands_numb[i]=brand_postion;       
            break;
        }
        if(brand_postion==brands && s_now[i]!=player_brand[brand_postion-1]||brand_postion>=brands){
            send_info(error_str_1,player->acceptfd);
            send_info(error_str_2,player->acceptfd);     
            out_brand(player,player1,player2,brands_info_last,brands_info);
            return 0;
        }
        i++;
        brand_postion++;
    }
    if(i==1){
        brands_info->brands_flag=player_brand[temp_brands_numb[0]];
    }else if(i==2){
        if(player_brand[temp_brands_numb[0]]!=player_brand[temp_brands_numb[1]]){
            send_info(error_str_2,player->acceptfd);
            out_brand(player,player1,player2,brands_info_last,brands_info);
            return 0;
        }else if(player_brand[temp_brands_numb[0]]=='w'&&player_brand[temp_brands_numb[1]=='W']){
            brands_info->kings=1;
        }else{
            brands_info->double_brands=1;
            brands_info->brands_flag=player_brand[temp_brands_numb[0]];
        }
    }else if(i==3){
        if(player_brand[temp_brands_numb[0]]==player_brand[temp_brands_numb[1]]&&player_brand[temp_brands_numb[0]]==player_brand[temp_brands_numb[2]]){
            brands_info->triple=1;
            brands_info->brands_flag=player_brand[temp_brands_numb[0]];
        }else{
            send_info(error_str_2,player->acceptfd);
            out_brand(player,player1,player2,brands_info_last,brands_info);
            return 0;
        }
    }else if(i==4){
        if(player_brand[temp_brands_numb[0]]==player_brand[temp_brands_numb[1]]&&player_brand[temp_brands_numb[0]]==player_brand[temp_brands_numb[2]]&&player_brand[temp_brands_numb[0]]==player_brand[temp_brands_numb[3]]){
            brands_info->bomb=1;
            brands_info->brands_flag=player_brand[temp_brands_numb[0]];
        }else if(player_brand[temp_brands_numb[0]]==player_brand[temp_brands_numb[1]]&&player_brand[temp_brands_numb[0]]==player_brand[temp_brands_numb[2]]||player_brand[temp_brands_numb[1]]==player_brand[temp_brands_numb[2]]&&player_brand[temp_brands_numb[1]]==player_brand[temp_brands_numb[3]]){
            brands_info->triple_and_one=1;
            brands_info->brands_flag=player_brand[temp_brands_numb[1]];
        }else{
            send_info(error_str_2,player->acceptfd);
            out_brand(player,player1,player2,brands_info_last,brands_info);
            return 0;
        }
    }else if(i==5){
        if(player_brand[temp_brands_numb[0]]==player_brand[temp_brands_numb[1]]&&player_brand[temp_brands_numb[0]]==player_brand[temp_brands_numb[2]]&&player_brand[temp_brands_numb[3]]==player_brand[temp_brands_numb[4]]||player_brand[temp_brands_numb[2]]==player_brand[temp_brands_numb[3]]&&player_brand[temp_brands_numb[2]]==player_brand[temp_brands_numb[4]]&&player_brand[temp_brands_numb[0]]==player_brand[temp_brands_numb[1]]){
            brands_info->triple_and_double=1;
            brands_info->brands_flag=player_brand[temp_brands_numb[2]];
        }else if((player_brand[temp_brands_numb[i-1]]<102)&&(player_brand[temp_brands_numb[0]]+1)==player_brand[temp_brands_numb[1]]&&(player_brand[temp_brands_numb[1]]+1)==player_brand[temp_brands_numb[2]]&&(player_brand[temp_brands_numb[2]]+1)==player_brand[temp_brands_numb[3]]&&(player_brand[temp_brands_numb[3]]+1)==player_brand[temp_brands_numb[4]]||judge_strgight_5(temp_brands_numb,player_brand)){
            brands_info->strgight=1;
            brands_info->brands_flag=player_brand[temp_brands_numb[0]];
        }else{
            send_info(error_str_2,player->acceptfd);
            out_brand(player,player1,player2,brands_info_last,brands_info);
            return 0;           
        }
    }else if(i==6){
        if(player_brand[temp_brands_numb[0]]==player_brand[temp_brands_numb[1]]&&player_brand[temp_brands_numb[0]]==player_brand[temp_brands_numb[2]]&&player_brand[temp_brands_numb[0]]==player_brand[temp_brands_numb[3]]&&player_brand[temp_brands_numb[4]]==player_brand[temp_brands_numb[5]]||player_brand[temp_brands_numb[2]]==player_brand[temp_brands_numb[3]]&&player_brand[temp_brands_numb[2]]==player_brand[temp_brands_numb[4]]&&player_brand[temp_brands_numb[2]]==player_brand[temp_brands_numb[5]]&&player_brand[temp_brands_numb[0]]==player_brand[temp_brands_numb[1]]){
            brands_info->bomb_and_double=1;
            brands_info->brands_flag=player_brand[temp_brands_numb[2]];
        }else if((player_brand[temp_brands_numb[i-1]]<102)&&judge_strgight_double_6(temp_brands_numb,player_brand)){
            brands_info->strgight_double=1;
            brands_info->brands_flag=player_brand[temp_brands_numb[0]];
        }else if(player_brand[temp_brands_numb[0]]==player_brand[temp_brands_numb[1]]&&player_brand[temp_brands_numb[0]]==player_brand[temp_brands_numb[2]]&&player_brand[temp_brands_numb[0]]==player_brand[temp_brands_numb[3]]&&player_brand[temp_brands_numb[4]]!=player_brand[temp_brands_numb[5]]||player_brand[temp_brands_numb[2]]==player_brand[temp_brands_numb[3]]&&player_brand[temp_brands_numb[2]]==player_brand[temp_brands_numb[4]]&&player_brand[temp_brands_numb[2]]==player_brand[temp_brands_numb[5]]&&player_brand[temp_brands_numb[0]]!=player_brand[temp_brands_numb[1]]){
            brands_info->bomb_and_two=1;
            brands_info->brands_flag=player_brand[temp_brands_numb[2]];
        }else if((player_brand[temp_brands_numb[i-1]]<102)&&judge_strgight_6(temp_brands_numb,player_brand)){
            brands_info->strgight=1;
            brands_info->brands_flag=player_brand[temp_brands_numb[0]];
        }else if(judge_airplane_6(temp_brands_numb,player_brand)){
            brands_info->airplane=1;
            brands_info->brands_flag=player_brand[temp_brands_numb[0]];
        }else{
            send_info(error_str_2,player->acceptfd);
            out_brand(player,player1,player2,brands_info_last,brands_info);
            return 0;           
        }
    }else if(i==7){
        if((player_brand[temp_brands_numb[i-1]]<102)&&judge_strgight_7(temp_brands_numb,player_brand)){
            brands_info->strgight=1;
            brands_info->brands_flag=player_brand[temp_brands_numb[0]];
        }else{
            send_info(error_str_2,player->acceptfd);
            out_brand(player,player1,player2,brands_info_last,brands_info);
            return 0;           
        }
    }else if(i==8){
        if((player_brand[temp_brands_numb[i-1]]<102)&&judge_strgight_double_8(temp_brands_numb,player_brand)){
            brands_info->strgight_double=1;
            brands_info->brands_flag=player_brand[temp_brands_numb[0]];
        }else if((player_brand[temp_brands_numb[i-1]]<102)&&judge_strgight_8(temp_brands_numb,player_brand)){
            brands_info->strgight=1;
            brands_info->brands_flag=player_brand[temp_brands_numb[0]];
        }else if(judge_airplane_8(temp_brands_numb,player_brand)){
            brands_info->airplane=1;
            brands_info->brands_flag=player_brand[temp_brands_numb[2]];
        }else if(judge_bomb_and_double_8(temp_brands_numb,player_brand,&brands_info->brands_flag)){
            brands_info->bomb_and_double=1;
        }else{
            send_info(error_str_2,player->acceptfd);
            out_brand(player,player1,player2,brands_info_last,brands_info);
            return 0;           
        }
    }else if(i==9){
        if((player_brand[temp_brands_numb[i-1]]<102)&&judge_strgight_9(temp_brands_numb,player_brand)){
            brands_info->strgight=1;
            brands_info->brands_flag=player_brand[temp_brands_numb[0]];
        }else if((player_brand[temp_brands_numb[i-1]]<102)&&judge_airplane_9(temp_brands_numb,player_brand)){
            brands_info->airplane=1;
            brands_info->brands_flag=player_brand[temp_brands_numb[0]];
        }else{
            send_info(error_str_2,player->acceptfd);
            out_brand(player,player1,player2,brands_info_last,brands_info);
            return 0;           
        }
    }else if(i==10){
        if((player_brand[temp_brands_numb[i-1]]<102)&&judge_strgight_10(temp_brands_numb,player_brand)){
            brands_info->strgight=1;
            brands_info->brands_flag=player_brand[temp_brands_numb[0]];
        }else if(judge_airplane_10(temp_brands_numb,player_brand,&brands_info->brands_flag)){
            brands_info->airplane=1;
        }else if((player_brand[temp_brands_numb[i-1]]<102)&&judge_strgight_double_10(temp_brands_numb,player_brand)){
            brands_info->strgight_double=1;
            brands_info->brands_flag=player_brand[temp_brands_numb[0]];
        }else{
            send_info(error_str_2,player->acceptfd);
            out_brand(player,player1,player2,brands_info_last,brands_info);
            return 0;           
        }
    }else if(i==11){
        if((player_brand[temp_brands_numb[i-1]]<102)&&judge_strgight_11(temp_brands_numb,player_brand)){
            brands_info->strgight=1;
            brands_info->brands_flag=player_brand[temp_brands_numb[0]];
        }else{
            send_info(error_str_2,player->acceptfd);
            out_brand(player,player1,player2,brands_info_last,brands_info);
            return 0;           
        }
    }else if(i==12){
        int temp_ret;
        if((player_brand[temp_brands_numb[i-1]]<102)&&judge_strgight_12(temp_brands_numb,player_brand)){
            brands_info->strgight=1;
            brands_info->brands_flag=player_brand[temp_brands_numb[0]];
        }else if(temp_ret=judge_airplane_12(temp_brands_numb,player_brand,&brands_info->brands_flag)){
            brands_info->airplane=temp_ret;
        }else if((player_brand[temp_brands_numb[i-1]]<102)&&judge_strgight_double_12(temp_brands_numb,player_brand)){
            brands_info->strgight_double=1;
            brands_info->brands_flag=player_brand[temp_brands_numb[0]];
        }else{
            send_info(error_str_2,player->acceptfd);
            out_brand(player,player1,player2,brands_info_last,brands_info);
            return 0;           
        }
    }else if(i==14){
        if((player_brand[temp_brands_numb[i-1]]<102)&&judge_strgight_double_14(temp_brands_numb,player_brand)){
            brands_info->strgight_double=1;
            brands_info->brands_flag=player_brand[temp_brands_numb[0]];
        }else{
            send_info(error_str_2,player->acceptfd);
            out_brand(player,player1,player2,brands_info_last,brands_info);
            return 0;           
        }
    }else if(i==15){
        if((player_brand[temp_brands_numb[i-1]]<102)&&judge_airplane_15(temp_brands_numb,player_brand,&brands_info->brands_flag)){
            brands_info->airplane=1;
        }else{
            send_info(error_str_2,player->acceptfd);
            out_brand(player,player1,player2,brands_info_last,brands_info);
            return 0;           
        }
    }else if(i==16){
        if((player_brand[temp_brands_numb[i-1]]<102)&&judge_strgight_double_16(temp_brands_numb,player_brand)){
            brands_info->strgight_double=1;
            brands_info->brands_flag=player_brand[temp_brands_numb[0]];
        }else if(judge_airplane_16(temp_brands_numb,player_brand,&brands_info->brands_flag)){
            brands_info->airplane=1;
        }else{
            send_info(error_str_2,player->acceptfd);
            out_brand(player,player1,player2,brands_info_last,brands_info);
            return 0;           
        }
    }else if(i==18){
        if((player_brand[temp_brands_numb[i-1]]<102)&&judge_strgight_double_18(temp_brands_numb,player_brand)){
            brands_info->strgight_double=1;
        }else if((player_brand[temp_brands_numb[i-1]]<102)&&judge_airplane_18(temp_brands_numb,player_brand)){
            brands_info->airplane=1;
        }else{
            send_info(error_str_2,player->acceptfd);
            out_brand(player,player1,player2,brands_info_last,brands_info);
            return 0;           
        }
    }else if(i==20){
        if(judge_airplane_20(temp_brands_numb,player_brand)){
            brands_info->airplane=1;
        }else if((player_brand[temp_brands_numb[i-1]]<102)&&judge_strgight_double_20(temp_brands_numb,player_brand)){
            brands_info->strgight_double=1;
        }else{
            send_info(error_str_2,player->acceptfd);
            out_brand(player,player1,player2,brands_info_last,brands_info);
            return 0;           
        }
    }else{
        send_info(error_str_2,player->acceptfd);
        out_brand(player,player1,player2,brands_info_last,brands_info);
        return 0;
    }
    brands_info->brands_num=i;
    if(((!memcmp(brands_info,brands_info_last,5))&&brands_info->brands_flag>brands_info_last->brands_flag)||brands_info->kings==1||(brands_info->bomb==1&&brands_info_last->bomb==0&&brands_info_last->kings==0)||(!memcmp(brands_info_last,&brands_info_temp,sizeof(brands_info_temp)))){    
        refresh_brands(temp_brands_numb,player->player_brand,i,&player->brands);
        replace_brand_to_player(s_now,i);
        sprintf(buff,"player[%s(%s)(%d)] out brands:%s",player->name,player->ID,player->brands,s_now);
        send_info(buff,player->acceptfd);
        send_info(buff,player1->acceptfd);
        send_info(buff,player2->acceptfd);
        *brands_info_last=*brands_info;
    }else{
        send_info(error_str_2,player->acceptfd);
        out_brand(player,player1,player2,brands_info_last,brands_info);
        return 0;
    }
    return 1;
}

//这里由于判断条件太多,发不出来我放在下一篇文中


/*
参数:int temp_brands_numb[]    出的牌在牌堆中的位置
    char player_brands[]    牌堆
    int numbs,int* brands   牌的数量
功能:更新玩家牌堆
返回值:无
*/
void refresh_brands(int temp_brands_numb[],char player_brands[],int numbs,int* brands){
    for(int i=0;i<numbs;i++){
        player_brands[temp_brands_numb[i]]=0;
    }
    char temp;
    int flag=0;
    int j;
    for(int i=0;i<*brands-1;i++){
        flag=0;
        for(j=0;j<*brands-i-1;j++){
            if(player_brands[j]==0){
                temp=player_brands[j];
                player_brands[j]=player_brands[j+1];
                player_brands[j+1]=temp;
                flag=1;         
            }
        }
        if(!flag)
            break;
    }
    *brands-=numbs;
}
/*
参数:char brand[] 原始牌堆
    int random_temp_brand[] 生成随机数的数组
    char player1[], char player2[], char player3[]  每个玩家的牌堆
功能:给每个玩家发牌同时将地主牌也发出去
返回值:返回地主值0/1/2
*/
int deal(char brand[],int random_temp_brand[], char player1[], char player2[], char player3[]){
    int temp;
    srand((unsigned)time(NULL));
    int landowner = rand() % 51 % 3;
    for(int i=0;i<51;i++){
        temp = i % 3;
        switch (temp){
            case 0:
                player1[i/3] = brand[random_temp_brand[i]];
                break;
            case 1:
                player2[i/3] = brand[random_temp_brand[i]];
                break;
            case 2:
                player3[i/3] = brand[random_temp_brand[i]];
        }
    }
    switch (landowner){
        case 0:
            player1[17] = brand[random_temp_brand[51]];
            player1[18] = brand[random_temp_brand[52]];
            player1[19] = brand[random_temp_brand[53]];
            break;
        case 1:
            player2[17] = brand[random_temp_brand[51]];
            player2[18] = brand[random_temp_brand[52]];
            player2[19] = brand[random_temp_brand[53]];
            break;
        case 2:
            player3[17] = brand[random_temp_brand[51]];
            player3[18] = brand[random_temp_brand[52]];
            player3[19] = brand[random_temp_brand[53]];
            break;
    }
    clear_brand(player1);
    clear_brand(player2);
    clear_brand(player3);
    return landowner;
}



/*
参数:char c_brand[] 
功能:删除牌中出过的牌
返回值:无
*/
void clear_brand(char c_brand[]){
    int number=20;
    int flags=0;
    char temp;
    if(c_brand[17]==0)
        number=17;
    for(int i=0;i<number-1;i++){
        for(int j=0;j<number-1-i;j++){
            if(c_brand[j]>c_brand[j+1]){
                temp=c_brand[j];
                c_brand[j]=c_brand[j+1];
                c_brand[j+1]=temp;
                flags=1;
            }
        }
        if(!flags)
            break;
    }
}

/*
参数:char r_brand[] 玩家的牌堆
    int brands 牌的数量
功能:将牌替换为玩家容易看的牌
返回值:无
*/
void replace_brand_to_player(char r_brand[],int brands){
    for(int i=0;i<brands;i++){
        switch(r_brand[i]){
            case 'a':
                r_brand[i]='T';
                break;
            case 'b':
                r_brand[i]='J';
                break;
            case 'c':
                r_brand[i]='Q';
                break;
            case 'd':
                r_brand[i]='K';
                break;
            case 'e':
                r_brand[i]='A';
                break;
            case 'f':
                r_brand[i]='2';
                break;
            case 'g':
                r_brand[i]='w';
                break;
            case 'h':
                r_brand[i]='W';
                break;
        }
    }
}


/*
参数:char r_brand[] 玩家的牌堆
    int brands 牌的数量
功能:将牌替换为电脑容易判断的牌
返回值:无
*/
void replace_brand_to_computer(char r_brand[],int brands){
    for(int i=0;i<brands;i++){
        switch(r_brand[i]){
            case 'T':
                r_brand[i]='a';
                break;
            case 'J':
                r_brand[i]='b';
                break;
            case 'Q':
                r_brand[i]='c';
                break;
            case 'K':
                r_brand[i]='d';
                break;
            case 'A':
                r_brand[i]='e';
                break;
            case '2':
                r_brand[i]='f';
                break;
            case 'w':
                r_brand[i]='g';
                break;
            case 'W':
                r_brand[i]='h';
                break;
        }
    }
}

/*
参数:int start 随机生成的开始值
    int end 随机生成的最大值
     int random_temp_brand[] 生成后的随机数放入该数组
      int temp_brand_nowpostion 当前生成了多少随机数
功能:生成0~53的随机数
返回值:当前生成的随机数值的多少
*/
int random_brand(int start, int end, int random_temp_brand[], int temp_brand_nowpostion)
{
    if ((start + 1) == end){
        random_temp_brand[temp_brand_nowpostion] = start;
        temp_brand_nowpostion++;
        return temp_brand_nowpostion;
    }
    if (start == end){
        return -1;
    }
    srand((unsigned)time(NULL));
    int n = start+rand() % (end - start);
    random_temp_brand[temp_brand_nowpostion] = n;
    temp_brand_nowpostion++;  
    int flag =0;
    if (n==start){
        start++;
        n=end;
        flag=1;
    }
    if(n==end-1){
        end--;
        flag=2;
    }
    temp_brand_nowpostion=random_brand(start, n, random_temp_brand, temp_brand_nowpostion);
    if (!flag)
        temp_brand_nowpostion=random_brand(n+1, end, random_temp_brand, temp_brand_nowpostion);
    return temp_brand_nowpostion;
}


/*
参数:int landowner 地主值
    players_t *player1,players_t *player2,players_t *player3 玩家信息
功能:给玩家发牌
返回值:无
*/
void set_brands(int landowner,players_t *player1,players_t *player2,players_t *player3){
    player1->brands=17;
    player2->brands=17;
    player3->brands=17;
    switch(landowner){
        case 0:
            player1->brands=20;
            strcpy(player1->ID,"landowner");
            strcpy(player2->ID,"farmer");
            strcpy(player3->ID,"farmer");
            break;
        case 1:
            player2->brands=20;
            strcpy(player2->ID,"landowner");
            strcpy(player1->ID,"farmer");
            strcpy(player3->ID,"farmer");
            break;
        case 2:
            player3->brands=20;
            strcpy(player3->ID,"landowner");
            strcpy(player2->ID,"farmer");
            strcpy(player1->ID,"farmer");
            break;
    }
}


/*
参数:players_t player 玩家信息
功能:给该玩家发送他的牌的信息
返回值:无
*/
void show(players_t player){
    replace_brand_to_player(player.player_brand,player.brands);
    char buff[128]={0};
    int num=1;
    sprintf(buff,"your brands(%s)(%d):",player.ID,player.brands);
    if(player.brands/10!=0){
        num=2;
    }
    for(int i=0;i<player.brands;i++){
        sprintf(&buff[12+strlen(player.ID)+2+num+2+2*i],"%c ",player.player_brand[i]);
    }
    send_info(buff,player.acceptfd);
}


/*
参数:void* arg  这个函数是线程处理函数,这里的参数传递了同一房间玩家的acceptfd
功能:开始游戏
返回值:无
*/
void *start_game(void* arg){
    players_info_t* players_info=(players_info_t*)arg;
    pthread_detach(pthread_self());
    srand((unsigned)time(NULL));
    int n = rand() % 54;
    char brand[54] = {'3','4','b','b','4','5','5','5','5','6','6','3','3','b','b','c','c','3','4','4','6','8','9','9','7','7','8','8','8','9','d','e','e','e','9','a','a','6','7','7','a','a','c','c','d','f','f','f','h','d','d','e','f','g',
    };
    players_t player1={
        .player_brand={0},
        .ID={0},
        .name={0},
    };
    players_t player2={
        .player_brand={0},
        .ID={0},
        .name={0},
    };
    players_t player3={
        .player_brand={0},
        .ID={0},
        .name={0},
    };
    char buff[128]={0};
    strcpy(player1.name,players_info->name_0);
    strcpy(player2.name,players_info->name_1);
    strcpy(player3.name,players_info->name_2);
    sprintf(buff,"game will brgin");
    send_all_info(buff,*players_info);
    player1.acceptfd=players_info->acceptfd_0;
    player2.acceptfd=players_info->acceptfd_1;
    player3.acceptfd=players_info->acceptfd_2;
    memset(players_info,0,sizeof(players_info));
    int random_temp_brand[54]={0};
    random_brand(0, 54, random_temp_brand, 0);
    int landowner=deal(brand,random_temp_brand,player1.player_brand,player2.player_brand,player3.player_brand);
    set_brands(landowner,&player1,&player2,&player3);
    show(player1);
    show(player2);
    show(player3);
    judge_order(landowner,&player1,&player2,&player3);
}


/*
参数:int landowner,players_t *player1,players_t *player2,players_t *player3 地主值和玩家信息
功能:判断出牌顺序及循环出牌
返回值:无
*/
int judge_order(int landowner,players_t *player1,players_t *player2,players_t *player3){
    brands_info_t brands_info_last;
    brands_info_t brands_info;
    memset(&brands_info,0,sizeof(brands_info));
    memset(&brands_info_last,0,sizeof(brands_info_last));
    char buff[128]={0};
    switch(landowner){
        case 0:
            sprintf(buff,"player[%s] is %s",player1->name,player1->ID);
            send_info(buff,player1->acceptfd);
            send_info(buff,player2->acceptfd);
            send_info(buff,player3->acceptfd);
            while(1){
                out_brand(player1,player2,player3,&brands_info_last,&brands_info);
                if(!player1->brands){
                    judge_win(*player1,*player2,*player3);
                    break;
                }
                out_brand(player2,player3,player1,&brands_info_last,&brands_info);
                if(!player2->brands){
                    judge_win(*player2,*player3,*player1);
                    break;
                }
                out_brand(player3,player1,player2,&brands_info_last,&brands_info);
                if(!player3->brands){
                    judge_win(*player3,*player2,*player1);
                    break;
                }
            }
            break;
        case 1:
            sprintf(buff,"player[%s] is %s",player2->name,player2->ID);
            send_info(buff,player1->acceptfd);
            send_info(buff,player2->acceptfd);
            send_info(buff,player3->acceptfd);
            while(1){
                out_brand(player2,player3,player1,&brands_info_last,&brands_info);
                if(!player2->brands){
                    judge_win(*player2,*player3,*player1);
                    break;
                }
                out_brand(player3,player1,player2,&brands_info_last,&brands_info);
                if(!player3->brands){
                    judge_win(*player3,*player1,*player2);
                    break;
                }
                out_brand(player1,player2,player3,&brands_info_last,&brands_info);
                if(!player1->brands){
                    judge_win(*player1,*player3,*player2);
                    break;
                }    
            }
            break;
        case 2:
            sprintf(buff,"player[%s] is %s",player3->name,player3->ID);
            send_info(buff,player1->acceptfd);
            send_info(buff,player2->acceptfd);
            send_info(buff,player3->acceptfd);
            while(1){
                out_brand(player3,player1,player2,&brands_info_last,&brands_info);
                if(!player3->brands){
                    judge_win(*player3,*player1,*player2);
                    break;
                }
                out_brand(player1,player2,player3,&brands_info_last,&brands_info);
                if(!player1->brands){
                    judge_win(*player1,*player2,*player3);
                    break;
                }
                out_brand(player2,player1,player3,&brands_info_last,&brands_info);
                if(!player2->brands){
                    judge_win(*player2,*player1,*player3);
                    break;
                }

            }
            break;
    }
}


/*
参数:players_t player1,players_t player2,players_t player3 每个玩家的信息
功能:判断哪种身份获胜
返回值:无
*/
int judge_win(players_t player1,players_t player2,players_t player3){
    char buff[128]={0};
    if(!strcmp(player1.ID,"landowner")){
        sprintf(buff,"player[%s(%s)] win",player1.name,player1.ID);
        send_info(buff,player1.acceptfd);
        send_info(buff,player2.acceptfd);
        send_info(buff,player3.acceptfd);
    }else{
        sprintf(buff,"player[%s(%s)] and player[%s(%s)] win",player1.name,player1.ID,player2.name,player2.ID);
        send_info(buff,player1.acceptfd);
        send_info(buff,player2.acceptfd);
        send_info(buff,player3.acceptfd);
    }
}

/*
参数:char room,int acceptfd,struct sockaddr_in clientaddr,char name[]  用户想要进入的房间以及用户信息
功能:创建房间
返回值:返回房间人数,房间人满返回-1
*/
int creat_room(char room,int acceptfd,struct sockaddr_in clientaddr,char name[]){
    char buff[128]={"room fill"};
    char text[200]={0};
    pthread_t tid;
    sprintf(text,"player[%s] have prepare", name);
    switch(room){
        case '0':
            if(players_info_0.acceptfd_0==0){
                players_info_0.acceptfd_0=acceptfd;
                players_info_0.clientaddr_0=clientaddr;
                strcpy(players_info_0.name_0,name);
                send_info(text,acceptfd);
                return 0;
            }else if(players_info_0.acceptfd_1==0){
                players_info_0.acceptfd_1=acceptfd;
                players_info_0.clientaddr_1=clientaddr;
                strcpy(players_info_0.name_1,name);
                send_info(text,acceptfd);
                send_info(text,players_info_0.acceptfd_0);
                return 1;
            }else if(players_info_0.acceptfd_2==0){
                players_info_0.acceptfd_2=acceptfd;
                players_info_0.clientaddr_2=clientaddr;
                strcpy(players_info_0.name_2,name);
                send_info(text,acceptfd);
                send_info(text,players_info_0.acceptfd_0);
                send_info(text,players_info_0.acceptfd_1);
                if ((errno = pthread_create(&tid, NULL, start_game, (void *)&players_info_0)) != 0)
                    PRINT_ERR("pthread create error");
                return 2;
            }else{
                send_info(buff,acceptfd);
                return -1;
            }
        case '1':
            if(players_info_1.acceptfd_0==0){
                players_info_1.acceptfd_0=acceptfd;
                players_info_1.clientaddr_0=clientaddr;
                strcpy(players_info_1.name_0,name);
                send_info(text,acceptfd);
                return 0;
            }else if(players_info_1.acceptfd_1==0){
                players_info_1.acceptfd_1=acceptfd;
                players_info_1.clientaddr_1=clientaddr;
                strcpy(players_info_1.name_1,name);
                send_info(text,acceptfd);
                send_info(text,players_info_1.acceptfd_0);
                return 1;
            }else if(players_info_1.acceptfd_2==0){
                players_info_1.acceptfd_2=acceptfd;
                players_info_1.clientaddr_2=clientaddr;
                strcpy(players_info_1.name_2,name);
                send_info(text,acceptfd);
                send_info(text,players_info_1.acceptfd_0);
                send_info(text,players_info_1.acceptfd_1);
                if ((errno = pthread_create(&tid, NULL, start_game, (void *)&players_info_1)) != 0)
                    PRINT_ERR("pthread create error");
                return 2;
            }else{
                send_info(buff,acceptfd);
                return -1;
            }
        case '2':
            if(players_info_2.acceptfd_0==0){
                players_info_2.acceptfd_0=acceptfd;
                players_info_2.clientaddr_0=clientaddr;
                strcpy(players_info_2.name_0,name);
                send_info(text,acceptfd);
                return 0;
            }else if(players_info_2.acceptfd_1==0){
                players_info_2.acceptfd_1=acceptfd;
                players_info_2.clientaddr_1=clientaddr;
                strcpy(players_info_2.name_1,name);
                send_info(text,acceptfd);
                send_info(text,players_info_2.acceptfd_0);
                return 1;
            }else if(players_info_2.acceptfd_2==0){
                players_info_2.acceptfd_2=acceptfd;
                players_info_2.clientaddr_2=clientaddr;
                strcpy(players_info_2.name_2,name);
                send_info(text,acceptfd);
                send_info(text,players_info_2.acceptfd_0);
                send_info(text,players_info_2.acceptfd_1);
                if ((errno = pthread_create(&tid, NULL, start_game, (void *)&players_info_2)) != 0)
                    PRINT_ERR("pthread create error");
                return 2;
            }else{
                send_info(buff,acceptfd);
                return -1;
            }
        case '3':
            if(players_info_3.acceptfd_0==0){
                players_info_3.acceptfd_0=acceptfd;
                players_info_3.clientaddr_0=clientaddr;
                strcpy(players_info_3.name_0,name);
                send_info(text,acceptfd);
                return 0;
            }else if(players_info_3.acceptfd_1==0){
                players_info_3.acceptfd_1=acceptfd;
                players_info_3.clientaddr_1=clientaddr;
                strcpy(players_info_3.name_1,name);
                send_info(text,acceptfd);
                send_info(text,players_info_3.acceptfd_0);
                return 1;
            }else if(players_info_3.acceptfd_2==0){
                players_info_3.acceptfd_2=acceptfd;
                players_info_3.clientaddr_2=clientaddr;
                strcpy(players_info_3.name_2,name);
                send_info(text,acceptfd);
                send_info(text,players_info_3.acceptfd_0);
                send_info(text,players_info_3.acceptfd_1);
                if ((errno = pthread_create(&tid, NULL, start_game, (void *)&players_info_3)) != 0)
                    PRINT_ERR("pthread create error");
                return 2;
            }else{
                send_info(buff,acceptfd);
                return -1;
            }
        default:
            break;
    }
}

/*
参数:char buff[],players_info_t players_info 要发送的信息及玩家信息
功能:给所有玩家发送信息
返回值:无
*/
int send_all_info(char buff[],players_info_t players_info){
    if (-1 == send(players_info.acceptfd_0, buff, 128, 0)){
        ERRLOG("send error");
    }
    if (-1 == send(players_info.acceptfd_1, buff, 128, 0)){
        ERRLOG("send error");
    }
    if (-1 == send(players_info.acceptfd_2, buff, 128, 0)){
        ERRLOG("send error");
    }
}


/*
参数:char buff[] 要发送的信息
    int acceptfd    玩家连接时的acceptfd
功能:给玩家发送信息
返回值:无
*/
int send_info(char buff[],int acceptfd){
    if (-1 == send(acceptfd, buff, 128, 0)){
        ERRLOG("send error");
    }
}


/*
参数:char buff[],int acceptfd 要发送的信息及玩家信息
功能:接受玩家信息
返回值:玩家推出返回0
*/
int recv_info(char buff[],int acceptfd){
    int nbytes;
    if (-1 == (nbytes = recv(acceptfd, buff, 128, 0))){
        ERRLOG("recv error");
    }
    if(nbytes==0)
        return 0;
}

int main(int argc, const char *argv[]){
    if(3 != argc){
        printf("Usage : %s <IP> <PORT>\n", argv[0]);
        return -1;
    }
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(-1 == sockfd){
        ERRLOG("socket error");
    }
    struct sockaddr_in serveraddr;
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(atoi(argv[2]));
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    socklen_t serveraddr_len = sizeof(serveraddr);
    int on = 1;
    if(-1 == setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))){
        ERRLOG("setsockopt error");
    }
    if(-1 == bind(sockfd, (struct sockaddr *)&serveraddr, serveraddr_len)){
        ERRLOG("bind error");
    }
    if(-1 == listen(sockfd, 12)){
        ERRLOG("listen error");
    }
    struct sockaddr_in clientaddr;
    socklen_t clientaddr_len = sizeof(clientaddr);
    char buff[128] = {0};
    int nbytes = 0;
    int acceptfd = 0;
    int max_fd = 0;
    int ret = 0;
    int i = 0;
    char text[200]={0};
    user_msg_t user_msg;
    memset(&user_msg, 0, sizeof(user_msg));
    fd_set readfds_temp;
    FD_ZERO(&readfds);
    FD_ZERO(&readfds_temp);
    FD_SET(sockfd, &readfds);
    max_fd = max_fd>sockfd?max_fd:sockfd;
    while(1){
        readfds_temp = readfds;
        if(-1 == (ret = select(max_fd+1, &readfds_temp, NULL, NULL, NULL))){
            ERRLOG("select error");
        }else if(0 == ret){
            continue;
        }else{
            for(i = 3; i < max_fd+1 && ret != 0; i++){
                if(FD_ISSET(i, &readfds_temp)){
                    ret--;
                    if(i == sockfd){
                        if(-1 == (acceptfd = accept(i, (struct sockaddr *)&clientaddr, &clientaddr_len))){
                            ERRLOG("accept error");
                        }
                        printf("客户端[%d]连接到服务器..\n", acceptfd);
                        FD_SET(acceptfd, &readfds);
                        max_fd = max_fd>acceptfd?max_fd:acceptfd;
                    }else{
                        memset(buff, 0, sizeof(buff));
                        char room;
                        if(-1 == (nbytes = recv(i, buff, sizeof(buff), 0))){
                            ERRLOG("recv error");
                        }else if(0 == nbytes){
                            printf("客户端[%d]断开了连接..\n", i);
                            close(i);
                            FD_CLR(i, &readfds);
                            continue;
                        }
                        if(!strcmp(buff, "quit")){
                            printf("客户端[%d]退出了..\n", i);
                            close(i);
                            FD_CLR(i, &readfds);
                            continue;
                        }if(!strncmp(buff, "start",5)){
                            room=buff[5];
                            creat_room(room,i,clientaddr,&buff[6]);
                            continue;
                        }
                        strcpy(buff, "please input start+num enter room");
                        if(-1 == send(i, buff, sizeof(buff), 0)){
                            ERRLOG("send error");
                        }
                    }
                }
            }
        }
    }
    close(sockfd);
    return 0;
}

客户端代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>

#define ERRLOG(msg)                                        \
    do                                                     \
    {                                                      \
        printf("%s %s %d:", __FILE__, __func__, __LINE__); \
        perror(msg);                                       \
        exit(-1);                                          \
    } while (0)

#define N 128

int main(int argc, const char *argv[]){
    if (3 != argc){
        printf("Usage : %s <IP> <PORT>\n", argv[0]);
        return -1;
    }
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == sockfd){
        ERRLOG("socket error");
    }
    struct sockaddr_in serveraddr;
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(atoi(argv[2]));
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    socklen_t serveraddr_len = sizeof(serveraddr);
    char buff[128] = {0};
    int nbytes = 0;
    pid_t pid;
    if (-1 == connect(sockfd, (struct sockaddr *)&serveraddr, serveraddr_len)){
        ERRLOG("connect error");
    }
    printf("与服务器建立连接成功..\n");
    char name[20]={0};
    puts("please input name(don't excced 20 char)");
    fgets(name,sizeof(name),stdin);
    name[strlen(name)-1]='\0';
    puts("please input (start+roomnum) begin(roomnum between 0 and 3)");
    if (-1 == (pid = fork())){
        ERRLOG("fork error");
    }
    else if (pid == 0){
        while (1){
            memset(buff, 0, sizeof(buff));
            fgets(buff, N, stdin);
            buff[strlen(buff) - 1] = '\0';
            if(!strncmp(buff,"start",5)){
                if(buff[5]<'0'||buff[5]>'3'){
                    puts("input error");
                    puts("input again");
                }
                strcat(buff,name);
            }
            if (-1 == send(sockfd, buff, sizeof(buff), 0)){
                ERRLOG("send error");
            }
        }
    }else{
            while(1){
                if (-1 == (nbytes = recv(sockfd, buff, sizeof(buff), 0))){
                    ERRLOG("recv error");
                }
                if(nbytes==0){
                    break;
                }
                printf("%s\n", buff);
            }
    }
    close(sockfd);

    return 0;
}

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
【资源说明】 基于Linux C++和socket网络编程的即时通信系统源码+项目说明(课程设计).zip 项目内容: 本项目使用C ++实现一个具备服务器端和客户端即时通信且具有私聊功能的聊天室 目的是学习C++网络开发的基本概念,同时也熟悉了Linux下的C++程序编译和简单MakeFile的编写 需求分析: 1.服务端:能够接受新的客户连接,并将每个客户端发来的信息,广播给对应的目标客户端 2.客户端:能够连接服务器,并向服务器发送消息,同时可以接受服务器发来的消息 服务端: 1.支持多个客户端接入,实现聊天室基本功能 2.启动服务,建立监听端口等待客户端连接 3.使用epoll机制实现并发,增加效率 4.客户端连接时,发送欢迎消息,并存储连接记录 5.客户端发送消息时,根据消息类型,广播给所有用户(群聊)或者指定用户(私聊) 6.客户端请求退出时,对相应连接信息进行清理 客户端: 1.连接服务器 2.支持用户输入消息,发送给服务端 3.接受并显示服务端发来的消息 4.退出连接 客户端需要两个进程分别支持以下功能: 子进程: 1.等待用户输入信息 2.将聊天信息写入管道(pipe),并发送给父进程 父进程: 1.使用epoll机制接收服务端发来的消息,并显示给用户,使用户看到其他用户的信息 2.将子进程发送的聊天信息从管道(pipe)中读取出来,并发送给客户端 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载使用,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值