Bootstrap

网络编程综合项目(聊天室,文件传输服务器,电子词典,五子棋)

使用UDP编程完成聊天室,文件传输服务器,电子词典,五子棋。

服务器:

/*===============================================
 *   文件名称:ser.c
 *   创 建 者:     
 *   创建日期:2023年08月28日
 *   描    述:
 ================================================*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <arpa/inet.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/wait.h>
#include <dirent.h>
#include <sys/stat.h>
#include <signal.h>
#include <pthread.h>
#include <sqlite3.h>
#include <dirent.h>
#include <fcntl.h>


#define ROWS 10
#define COLS 10


typedef struct wm{
    int row;
    int col;
    int flag;

    int type;
    char name[30];
    char destname[30];
    char data[100];
}MSG;

typedef struct node{
    struct wm user;
    struct sockaddr_in addr;
    struct node * next;
}*linklist,linknode;
//五子棋行列
typedef struct {
    int row;
    int col;
}TP;
//回调函数
typedef struct {
    int fd;
    int len; 
    struct wm his;
    struct sockaddr_in hddr;
}call;

linklist list_create(){
    linklist H=(linklist)malloc(sizeof(linknode));
    if(NULL==H){
        printf("create fail\n");
        return NULL;
    }
    H->next=NULL;
    return H;
}

void insert_linklist(MSG msg,struct sockaddr_in cliaddr,linklist p){
    linklist t=p;
    while(t->next!=NULL){
        t=t->next;
    }
    linklist new=(linklist)malloc(sizeof(linknode));
    new->addr=cliaddr;
    new->user=msg;
    new->next=NULL;
    t->next=new;
    return;
}

void delete_linklist(linklist p,MSG*msg){
    linklist l=p;
    linklist pt=NULL;
    if(p->next==NULL) {
        perror("linklist NULL");
        exit(-1);
    }
    while(l->next!=NULL){
        if(strcmp(l->next->user.name,msg->name)==0)
        {

            if(l->next->next==NULL){
                l->next=NULL; 
                printf("%s从链表中删除\n",msg->name);
                break;
            }  
            pt=l->next;
            l->next=l->next->next;
            printf("%s从链表中删除\n",msg->name);
            free(pt);
            break;
        }
        else
        {
            l=l->next;
        }
    } 
}


void zhuce(int fd,MSG*msg,sqlite3*db,struct sockaddr_in cliaddr,int len){

    char *errmsg;
    char sql[200]={0};
    sprintf(sql,"INSERT INTO usr VALUES('%s','%s')",msg->name,msg->data);
    printf("%s\n",sql);
    if( sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
    { 

        sprintf(msg->data,"用户名 %s 已存在",msg->name);
        printf("%s\n",msg->data);
    }
    else
    {
        sprintf(msg->data,"注册成功!!");
        printf("%s\n",msg->data);
    }

    if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&cliaddr,len)==-1){
        perror("send error\n");
        exit(-1);
    }
    return;
}

int denglu(int fd,MSG*msg,sqlite3*db,struct sockaddr_in cliaddr,int len,linklist p){
    char *errmsg;
    char sql[200]={0};
    char **result;
    int row;
    int col;
    printf("%s正在登陆\n",msg->name);
    sprintf(sql,"select * from usr where name = '%s' and pass = '%s'",msg->name,msg->data);
    if( sqlite3_get_table(db,sql,&result,&row,&col,&errmsg)!=SQLITE_OK)
    { 
        printf("%s",errmsg);
        exit(-1);
    }
    else
    {
        if(row==0){
            sprintf(msg->data,"用户名或密码错误");
            if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&cliaddr,len)==-1){
                perror("send error\n");
                exit(-1);
            }
            return -1;
        } 
        else
        {
            sprintf(msg->data,"denglu success");
            if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&cliaddr,len)==-1){
                perror("send error\n");
                exit(-1);
            }

            return 1;
        }

    }
}



void chat(int fd,MSG*msg,sqlite3*db,struct sockaddr_in cliaddr,int len,linklist p){

   /* linklist pp=p->next;
   while(pp!=NULL)
     {   
                sprintf(msg->data,"%s上线啦\n",msg->name);
                printf("%s\n",msg->data);  
                if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&pp->addr,sizeof(pp->addr)) < 0)
                {
                    perror("sendto\n");
                    exit(-1);
                }
                pp=pp->next;

            }
   */

    char sql[300];
    char *errmsg;
    char date[100]={0};
    linklist q,m,n;
    q=p->next;
    m=p->next;
    n=p->next;
    if(q==NULL)
    {
        perror("linklist NULL");
        exit(-1);
    }

    time_t tm;
    struct tm *tmp_ptr = NULL;
    time(&tm);
    tmp_ptr = localtime(&tm);
    sprintf (date,"%d-%02d-%02d %02d:%02d:%02d", (1900+tmp_ptr->tm_year), (1+tmp_ptr->tm_mon), tmp_ptr->tm_mday, tmp_ptr->tm_hour, tmp_ptr->tm_min, tmp_ptr->tm_sec);

    sprintf(sql,"insert into record values('%s','%s','%s')",msg->name,date,msg->data);
    printf("%s",date);

    if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK){
        printf("%s\n",errmsg);
        exit(-1);
    }

    while(q!=NULL)
    {   
        if(strcmp(q->user.name,msg->name)==0){
            q=q->next;
        }
        else{
            if(strcmp(msg->data,"quit")==0){
                sprintf(msg->data,"[%s]已离线",msg->name);
                delete_linklist(p,msg);
                printf("%s is quit\n",msg->name);
            }else{
                char temp[100]={0};
                strcpy(temp,msg->data);
                sprintf(msg->data,"%s\n[%s]:%s\n",date,msg->name,temp);
                printf("%s\n",msg->data);  
            }
            if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&q->addr,sizeof(q->addr)) < 0)
            {
                perror("sendto\n");
                exit(-1);
            }
            else{
                q= q->next;
            }

        }
    }

    return;
}


//2. 列数3.列的结果 4.列的名字
int hiscallback(void *arg,int num,char** value,char ** name){
    call s=*(call*)arg;
    sprintf(s.his.data,"%s [%s]:%s",value[1],value[0],value[2]);
    sendto(s.fd,&s.his,sizeof(MSG),0,(struct sockaddr *)&(s.hddr),s.len);
    return 0;
}


int history(int fd,MSG msg,sqlite3*db,struct sockaddr_in cliaddr,int len){
    printf("find  chathistory\n");
    call c;
    c.fd=fd;
    c.hddr=cliaddr;
    c.len=len;
    c.his=msg;
    char *errmsg;

    if( sqlite3_exec(db ,"select * from record", hiscallback , (void*)&c , &errmsg)!=SQLITE_OK)
    { 
        printf("error:%s\n",errmsg);
        sqlite3_free(errmsg);
        exit(-1);
    }
    //解决阻塞
    strcpy(msg.data, "*");
    if(sendto(fd,&msg,sizeof(MSG),0,(struct sockaddr * )&cliaddr,len)==-1)
    {
        perror("fail to send");
        exit(-1);
    }
    return 1;

}

void siliao(int fd,MSG*msg,sqlite3*db,struct sockaddr_in cliaddr,int len,linklist q){
    printf("in siliao\n");
    char sql[300];
    char *errmsg;
    char date[100]={0};
    linklist m=q->next;
    linklist n=q->next;

    if(m==NULL){
        printf("kong linklist\n");   
        perror("linklist"); 
        exit(-1);
    }
    else{
        printf("%s\n",m->user.name);

        printf("链表不为空\n");
    }


    while(m!=NULL)
    {
        if(strcmp(m->user.name,msg->destname)==0){
            char temp[100]={0};
            strcpy(temp,msg->data);
            sprintf(msg->data,"%s to %s:%s",msg->name,msg->destname,temp);
            printf("%s\n",msg->data);

            if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&m->addr,sizeof(m->addr)) < 0)
            {
                perror("sendto\n");
                exit(-1);
            }
            else{ printf("send success\n");
    time_t tm;
    struct tm *tmp_ptr = NULL;
    time(&tm);
    tmp_ptr = localtime(&tm);
    sprintf (date,"%d-%02d-%02d %02d:%02d:%02d", (1900+tmp_ptr->tm_year), (1+tmp_ptr->tm_mon), tmp_ptr->tm_mday, tmp_ptr->tm_hour, tmp_ptr->tm_min, tmp_ptr->tm_sec);

    sprintf(sql,"insert into record values('%s','%s','%s')",msg->name,date,msg->data);
    printf("%s",sql);

    if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK){
        printf("%s\n",errmsg);
        exit(-1);
    }
                break;
            } 

        }

        else{
            m=m->next;
            printf("goto next\n");
        }

    }

    if(m==NULL){
        printf("destname not exit\n");
        sprintf(msg->data,"...[%s] not online",msg->destname);
        if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&cliaddr,len) < 0)
        {
            perror("sendto\n");
            exit(-1);
        }
    }
}
//电子字典
int zidian(int fd,MSG*msg,sqlite3*db,struct sockaddr_in cliaddr,int len){

 printf("%s is finding now\n",msg->name);
   char *m; 
   char date[100]={0};
   char *errmsg;
   char word[100]={0};
   int wlen=0;
   char sql[300];
   char buf[100];
   char temp[100];
   FILE *fp=fopen("./dict.txt","r");
   if(fp==NULL){
   perror("open dict fail\n");
   exit(-1);
   }
   printf("open dict success\n");
  
   strcpy(word,msg->data);
   wlen=strlen(word);
  
   printf("%s,%d\n",word,wlen);

   while(1)
   {
   char*p=fgets(buf,100,fp);
   if(p == NULL){
   strcpy(msg->data,"没有这个单词");

if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&cliaddr,len) < 0)
  {
     perror("sendto\n");
     exit(-1);
        }

    break;
   }
    
   strcpy(temp,buf);  
   char*q= strtok(buf," ");

   if(strcmp(q,msg->data)==0){
   printf("strok:%s\n",q);
   printf("buf:%s\n",buf);
   printf("temp:%s\n",temp);
   
   m=temp+wlen; 
   while(*m==' ')
   {
   m++;
   }
   strcpy(msg->data,m);

if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&cliaddr,len) < 0)
  {
     perror("sendto\n");
     exit(-1);
        }

   time_t tm;
    struct tm *tmp_ptr = NULL;
    time(&tm);
    tmp_ptr = localtime(&tm);
    sprintf (date,"%d-%02d-%02d %02d:%02d:%02d", (1900+tmp_ptr->tm_year), (1+tmp_ptr->tm_mon), tmp_ptr->tm_mday, tmp_ptr->tm_hour, tmp_ptr->tm_min, tmp_ptr->tm_sec);
 
   sprintf(sql,"insert into zidianrecord values('%s','%s','%s')",msg->name,date,word);
    printf("%s",date);

   if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK){
    printf("%s\n",errmsg);
    return -1;
   }
   fclose(fp);
   return 1;
   }

   }
    
    fclose(fp); 
   return -1;

}

//2. 列数3.列的结果 4.列的名字
int zidiancallback(void *arg,int num,char** value,char ** name){
    call d=*(call*)arg;
    sprintf(d.his.data,"%s 用户: %s  查找单词: %s",value[1],value[0],value[2]);
    sendto(d.fd,&d.his,sizeof(MSG),0,(struct sockaddr *)&(d.hddr),d.len);
     return 0;
}


int zidianhis(int fd,MSG msg,sqlite3*db,struct sockaddr_in cliaddr,int len){
    call z;
    z.fd=fd;
    z.hddr=cliaddr;
    z.len=len;
    z.his=msg;
    char *errmsg;
    char sql[200]={0};

    sprintf(sql,"select * from zidianrecord where name = '%s'",msg.name);
    if( sqlite3_exec(db , sql , zidiancallback , (void*)&z , &errmsg)!=SQLITE_OK)
    { 
    printf("error:%s\n",errmsg);
		sqlite3_free(errmsg);
    exit(-1);
    }

    //解决阻塞
     strcpy(msg.data, "*");
    if(sendto(fd,&msg,sizeof(MSG),0,(struct sockaddr *)&cliaddr,len)==-1){
		perror("fail to send");
		exit(-1);
	}

    return 1;
}


//文件服务器
void mulu(int fd,MSG *msg,struct sockaddr_in cliaddr,int len){
    
        DIR*dirp=opendir(msg->data);
        struct dirent* file;
        while(file=readdir(dirp)){
         strcpy(msg->data,file->d_name);                 
    if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&cliaddr,len)==-1){
		perror("fail to send");
		exit(-1);
	}

}
     strcpy(msg->data, "*");
    if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&cliaddr,len)==-1){
		perror("fail to send");
		exit(-1);
	}
   return;
}
void scwj(int fd,MSG *msg,struct sockaddr_in cliaddr,int len){
  
    int ffd=open(msg->name,O_WRONLY|O_CREAT,0666);           
      if(fd==-1)
      {
           printf("open file fail\n");

      }         

        if(0==strcmp(msg->data,"*"))
          {
          printf("下载完成\n");
         close(ffd);
            return;
          }
          write(ffd,msg->data,strlen(msg->data));

}

void xzwj(int fd,MSG *msg,struct sockaddr_in cliaddr,int len){
        strcat(msg->data,msg->name);
        printf("打开%s\n",msg->data);
        int ffd = open(msg->data,O_RDONLY);
        int ret=0;
            memset(msg->data,0,100);
        while(1){
       ret=read(ffd,msg->data,100);
        if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&cliaddr,len)==-1){
		perror("fail to send");
		exit(-1);
	}
     if(ret==0){

     strcpy(msg->data, "*");
    if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&cliaddr,len)==-1){
		perror("fail to send");
		exit(-1);
      	}
       break;
     }
            memset(msg->data,0,100);
  }
    close(ffd);
    return;
}


void gaipass(int fd,MSG *msg,sqlite3*db,struct sockaddr_in cliaddr,int len){
    printf("xiugaGi: pass:%s\n name:%s",msg->data,msg->name);
    char*errmsg;
    char sql[200]={0};
    sprintf(sql,"update usr set pass = '%s' where name = '%s'",msg->data,msg->name);          
    if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
    {
     sprintf(msg->data,"修改失败");   
     printf("%s",errmsg);
     exit(-1);
    }
    else{
     sprintf(msg->data,"修改成功");   
    }
    
    if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&cliaddr,len)==-1){
		perror("fail to send");
		exit(-1);
	}

}


void zhuxiao(int fd,MSG *msg,sqlite3*db,struct sockaddr_in cliaddr,int len){
    char*errmsg;
    char sql[200]={0};
    sprintf(sql,"delete from usr where name = '%s'",msg->name);          
    if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
    {
     sprintf(msg->data,"注销失败...");   
     printf("%s",errmsg);
     exit(-1);
    }
    else{
     sprintf(msg->data,"注销成功!");   
    }
    
    if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&cliaddr,len)==-1){
		perror("fail to send");
		exit(-1);
	}

}

//五子棋
int f=1;
void shunxu(int fd,MSG msg,struct sockaddr_in cliaddr,int len){
    
    msg.flag=f;
    printf("%d\n",f);
    if(msg.flag==1)
    {
        sprintf(msg.data,"你是先手");  
    }
    else{
        sprintf(msg.data,"你是后手");  

    }

    if(sendto(fd,&msg,sizeof(MSG),0,(struct sockaddr * )&cliaddr,len)==-1)
    {
        perror("send error");
        exit(-1);
    }
    f++;
}




void game(int fd,MSG  msg,linklist qi,struct sockaddr_in cliaddr,int len){
    printf("进入五子棋游戏\n");

    TP tp;
    linklist qt;
    qt=qi->next;

    if(qt==NULL)
    {
        perror("linklist NULL");
        exit(-1);
    }

    tp.row=msg.row;
    tp.col=msg.col;

    while(qt!=NULL)
    {   
        if(strcmp(qt->user.name,msg.name)==0){
            printf("linknext\n");
            qt=qt->next;
        }
        else{

            printf("send game\n");
            if(sendto(fd,&tp,sizeof(TP),0,(struct sockaddr *)&qt->addr,sizeof(qt->addr)) < 0)
            {
                perror("sendto\n");
                exit(-1);
            }
            else{

                break;
            }


        }
    }

}


int main(int argc, const char *argv[]){

   MSG msg;
   sqlite3 *db;
   char *errmsg1 = NULL;
   char *errmsg2 = NULL;
   char *errmsg3 = NULL;
    //入参合理性检查
    if(3 != argc){
        printf("Usage : %s <IP> <PORT>\n", argv[0]);
        exit(-1);
    }


    if(sqlite3_open("my.db",&db)!=SQLITE_OK)
    {
        printf("%s\n",sqlite3_errmsg(db));
      
        return -1;
    }
    else{
        
 printf("打开数据库成功\n"); 
    char *sql1 = "create table if not exists usr(name text primary key,pass text)";
  int ret1 = sqlite3_exec(db, sql1, NULL, NULL, &errmsg1);
	if (ret1!= SQLITE_OK)
	{
		printf ("用户表创建失败:%s\n", errmsg1);
		return -1;
	}


    char *sql2 = "create table if not exists record(name text , data text , word text)";
  int ret2 = sqlite3_exec(db, sql2, NULL, NULL, &errmsg2);
	if (ret2 != SQLITE_OK)
	{
		printf ("用户表创建失败:%s\n", errmsg2);
		return -1;
	}
    
     char *sql3= "create table if not exists zidianrecord(name text , data text , word text)";
  int ret3 = sqlite3_exec(db, sql3, NULL, NULL, &errmsg3);
	if (ret3 != SQLITE_OK)
	{
		printf ("用户表创建失败:%s\n", errmsg3);
		return -1;
	}

    }

    //创建用户数据报套接字
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(-1 == fd){
        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);

    //3.绑定
    if(-1 == bind(fd, (struct sockaddr *)&serveraddr, serveraddr_len)){
        ERRLOG("bind error");
    }

    //定义结构体保存客户端的信息
    //如果使用UDP时不保存客户端的网络信息结构体
    //可以接受到客户端发来的数据  但是没法回信给客户端 因为sendto的后两个参数需要用到
    struct sockaddr_in cliaddr;
    int len = sizeof(cliaddr);

    linklist p=list_create();//群聊
    linklist q=list_create();//私聊
    linklist qi=list_create();//五子棋
    while(1){
        int ret =recvfrom(fd,&msg,sizeof(MSG), 0, (struct sockaddr *)&cliaddr, &len);
        if(ret>0)
        {
 
            switch(msg.type)
            {
                case 1:
                    zhuce(fd,&msg,db,cliaddr,len);
                    break;
                case 2:
                    if(denglu(fd,&msg,db,cliaddr,len,p)==1){
                        insert_linklist(msg,cliaddr,p);
                        insert_linklist(msg,cliaddr,q);
                        break;
                    }else{
                        break;}
                case 3:
                    chat(fd,&msg,db,cliaddr,len,p);
                    break;
                case 4:
                    history(fd,msg,db,cliaddr,len);
                    break;
                case 5:
                    siliao(fd,&msg,db,cliaddr,len,q);
                    break;
                case 6:
                    zidian(fd,&msg,db,cliaddr,len);
                    break;
                case 7:
                    zidianhis(fd,msg,db,cliaddr,len);
                    break;
                case 8:
                    mulu(fd,&msg,cliaddr,len);
                    break;
                case 9:
                    scwj(fd,&msg,cliaddr,len);
                    break;
                case 10:
                    xzwj(fd,&msg,cliaddr,len);
                    break;
                case 11:
                    gaipass(fd,&msg,db,cliaddr,len);
                    break;
                case 12:
                    zhuxiao(fd,&msg,db,cliaddr,len);
                    break;
                 case 13:
                    shunxu(fd,msg,cliaddr,len);
                    insert_linklist(msg,cliaddr,qi);
                    break;
                case 14:
                    game(fd,msg,qi,cliaddr,len);
                    break;
defalut:
                    printf("recv error\n");
            }

        }

    }

    close(fd); 
    return 0;
}




 客户端

/*===============================================
 *   文件名称:cli.c
 *   创 建 者:     
 *   创建日期:2023年08月28日
 *   描    述:
 ================================================*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/wait.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>

#define ROWS 10
#define COLS 10




typedef struct wm{
    int row;
    int col;
    int flag;
    int type;
    char name[30];
    char destname[30];
    char data[100];
}MSG;

typedef struct {
    int row;
    int col;
}TP;


int show_connect()
{
	printf("正在连接服务器,请稍候...\n");
    int i, num = 1;
    const char* pic = "|/-\\"; //简单动画特效
 
    while(1)
    {   
        if(101 == num)    //当num自增到101时,进度条已满。显示Loading成功信息,并跳出死循环。
        {   
			break;
        }    
        printf("[");
        for(i = 0; i < num/10; i++)    //当进度前进10个点时,刷新一次进度条。
            printf("*");    //以'*'充当进度条。
        printf("]"); 
        printf("%d%%...%c\r", num++, pic[num%4]);   //'\r'为回车符。
        fflush(stdout);    //清空标准输出缓冲区中多余的数据。
        usleep(40000);    //这里通过修改睡眠时间来控制进度条更新速度。
    }   
	
    return 0;
}





//动态显示进度条
int show_login()
{
	printf("正在登陆,请稍候...\n");
    int i, num = 1;
    const char* pic = "|/-\\"; //简单动画特效

    while(1)
    {
        if(101 == num)    //当num自增到101时,进度条已满。显示Loading成功信息,并跳出死循环。
        {
             printf("\n登陆成功!!\n");
             sleep(1);
			break;
        }

        printf("[");
        for(i = 0; i < num/10; i++)    //当进度前进10个点时,刷新一次进度条。
            printf("*");    //以'*'充当进度条。
        printf("]");

        printf("%d%%...%c\r", num++, pic[num%4]);   //'\r'为回车符。
        fflush(stdout);    //清空标准输出缓冲区中多余的数据。
        usleep(40000);    //这里通过修改睡眠时间来控制进度条更新速度。
    }

    return 0;
}



void zhuce(int fd,MSG*msg,struct sockaddr_in saddr,int len){
    msg->type=1;
    printf("\033[1;33m输入网名\n");
    fgets(msg->name,30,stdin);
    msg->name[strlen(msg->name)-1]='\0';

    printf("\033[0;35m输入密码\n");
    fgets(msg->data,100,stdin);
    msg->data[strlen(msg->data)-1]='\0';


    if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
    {
        perror("send 失败");
        exit(-1);
    }
    if(recvfrom(fd,msg,sizeof(MSG),0,NULL,NULL)==-1)
    {
        perror("recv 失败");
        exit(-1);
    }
    printf("%s\n",msg->data);
    return;
}


int denglu(int fd,MSG*msg,struct sockaddr_in saddr,int len){
    msg->type=2;
    printf("\033[1;36m输入网名\n");
    fgets(msg->name,30,stdin);
    msg->name[strlen(msg->name)-1]='\0';

    printf("\033[0;33m输入密码\n");
    fgets(msg->data,100,stdin);
    msg->data[strlen(msg->data)-1]='\0';


    if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
    {
        perror("send 失败");
        exit(-1);
    }

    if(recvfrom(fd,msg,sizeof(MSG),0,NULL,NULL)==-1)
    {
        perror("recv 失败");
        exit(-1);
    }

    if(strncmp(msg->data,"denglu success",14)==0){
        show_login();
        printf("\033[0;35m%s,欢迎回来!!\n",msg->name);    
        return 1;
    }else{
        printf("\033[1;33m%s\n",msg->data);    
        return -1;
    }
}


void chat(int fd,MSG*msg,struct sockaddr_in saddr,int len){

    MSG*temp; 
    msg->type=3;
/*    if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
    {
        perror("历史失败");
        exit(-1);
    }
*/
    pid_t pid= fork();     
    if(pid<0){
        perror("fork");
        exit(-1);
    }
    else if(pid==0)
    {
        while(1)
        {
            //接收
            //   memset(temp->name,0,sizeof(temp->data));
            //   memset(temp->data,0,sizeof(temp->data));
            if(recvfrom(fd,temp,sizeof(MSG),0,NULL,NULL)==-1)
            {
                perror("recv 失败");
                exit(-1);
            }
            printf("\033[1;33m%s\n",temp->data);
        }
    }

    else{
        //发送
        while(1){
            //   memset(msg->data,0,sizeof(msg->data));
            fgets(msg->data,100,stdin);
            msg->data[strlen(msg->data)-1]='\0';

            if(strcmp(msg->data,"quit")==0)
            {
            if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
            {
                perror("send 失败");
                exit(-1);
            }
                kill(pid,SIGKILL);     
                wait(NULL);  
                break;
            }
            if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
            {
                perror("send 失败");
                exit(-1);
            }
        }
    }
  //  close(fd);
    return;
}



int history(int fd,MSG*msg,struct sockaddr_in saddr,int len){
    msg->type=4;
    if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
    {
        perror("历史失败");
        exit(-1);
    }
    while(1){

           memset(msg->data,0,sizeof(msg->data));
        if(recvfrom(fd,msg,sizeof(MSG),0,(struct sockaddr*)&saddr,&len)==-1)
        {
            perror("recv 失败");
            exit(-1);
        }
        //解决阻塞 
        if(0==strcmp(msg->data,"*"))
        {
            break;
        }

        printf("%s\n",msg->data);    
    }

    return 1;

}

void siliao(int fd,MSG*msg,struct sockaddr_in saddr,int len){

   MSG*temp; 
   msg->type=5;
   printf("请输入你要连接人的名字\n");
   fgets(msg->destname,30,stdin);
   msg->destname[strlen(msg->destname)-1]='\0';
  
             printf("输入你想要发送的数据\n");
   pid_t pid=fork();
  if(pid<0){
   perror("fork\n");
   exit(-1);
  }
 else if(pid==0)
    {
        while(1)
        {
            //接收
            //   memset(temp->name,0,sizeof(temp->data));
            //   memset(temp->data,0,sizeof(temp->data));
            if(recvfrom(fd,temp,sizeof(MSG),0,NULL,NULL)==-1)
            {
                perror("recv 失败");
                exit(-1);
            }
            printf("\033[1;33m%s\n",temp->data);
        }
    }

    else{
        //发送
        while(1){
            //   memset(msg->data,0,sizeof(msg->data));
            fgets(msg->data,100,stdin);
            msg->data[strlen(msg->data)-1]='\0';

            if(strcmp(msg->data,"quit")==0)
            {

                kill(pid,SIGKILL);     
                wait(NULL);
               exit(1);  
                break;
            }
            if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
            {
                perror("send 失败");
                exit(-1);
            }
        }
    }
   close(fd);
    return;

}


void zidian(int fd,MSG*msg,struct sockaddr_in saddr,int len){

 msg->type=6;
    while(1)
{
      memset(msg->data,0,100);
    printf("\033[1;32m输入要查找的单词(q)结束\n");
      fgets(msg->data,100,stdin);
     msg->data[strlen(msg->data)-1]='\0';
 
    if (0 == strcmp(msg->data, "q"))
		{
            printf("quit \n");
			break;
		}
  
    
    if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
    {
    perror("send 失败");
    exit(-1);
    }

    if(recvfrom(fd,msg,sizeof(MSG),0,(struct sockaddr*)&saddr,&len)==-1)
    {
    perror("recv 失败");
    exit(-1);
    }
    printf("\033[0;33m%s\n",msg->data);   
  } 

  
//close(fd);
return;
}


int zidianhis(int fd,MSG*msg,struct sockaddr_in saddr,int len){
   msg->type=7;

   if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
   {
       perror("历史失败");
       exit(-1);
   }
   while(1){
       if(recvfrom(fd,msg,sizeof(MSG),0,(struct sockaddr*)&saddr,&len)==-1)
       {
           perror("recv 失败");
           exit(-1);
       }
       //解决阻塞 
       if(0==strcmp(msg->data,"*"))
       {
           break;
       }

       printf("%s\n",msg->data);    
   }

   return 1;

}


void mulu(int fd,MSG*msg,struct sockaddr_in saddr,int len){

        msg->type=8;
         
    printf("\033[1;32m输入要查看的目录\n");
      fgets(msg->data,100,stdin);
     msg->data[strlen(msg->data)-1]='\0';
   

      if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
     {
       perror("发送失败");
       exit(-1);
     }
     while(1){
       if(recvfrom(fd,msg,sizeof(MSG),0,(struct sockaddr*)&saddr,&len)==-1)
       {
           perror("recv 失败");
           exit(-1);
       }
       if(0==strcmp(msg->data,"*"))
       {
           break;
       }
       printf("%s\n",msg->data);

     } 

}

void scwj(int fd,MSG*msg,struct sockaddr_in saddr,int len){
        msg->type=9;
         char buf[100]={0};
         char buf2[100]={0};
    
      printf("请输入你要上传到服务器哪个路径\n");
      fgets(buf,100,stdin);  
       buf[strlen(buf)-1]='\0';
    
       printf("请输入你要上传的文件名\n");
      fgets(buf2,100,stdin);  
       buf2[strlen(buf2)-1]='\0';
        
       strcat(buf,buf2);
         strcpy(msg->name,buf);

    int ffd = open(buf2,O_RDONLY);
           int ret=-1;
               memset(msg->data,0,100);
            while(1){
           ret=read(ffd,msg->data,100);
            if(ret==0){
            strcpy(msg->data, "*");
    sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&saddr,len);
            printf("上传完成\n");
            return;
               }
    sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&saddr,len);
        memset(msg->data,0,100);
    }
      close(ffd);

}
void xzwj(int fd,MSG*msg,struct sockaddr_in saddr,int len){
        msg->type=10;

      printf("请输入你要下载服务器哪个路径下的文件\n");
      fgets(msg->data,100,stdin);  
       msg->data[strlen(msg->data)-1]='\0';
    
       printf("请输入你要下载的文件名\n");
      fgets(msg->name,100,stdin);  
       msg->name[strlen(msg->name)-1]='\0';


       if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
     {
       perror("发送失败");
       exit(-1);
     }
       int ffd=open(msg->name,O_RDWR|O_CREAT,0666);
       
       while(1){

       if(recvfrom(fd,msg,sizeof(MSG),0,(struct sockaddr*)&saddr,&len)==-1)
       {
           perror("recv 失败");
           exit(-1);
       }

       if(0==strcmp(msg->data,"*"))
       {
           break;
       }
       write(ffd,msg->data,strlen(msg->data)); 
      

       }
       printf("下载完成\n");
       close(ffd);
       return;
}
void gaipass(int fd,MSG*msg,struct sockaddr_in saddr,int len){
      msg->type=11;
      printf("请输入你要修改的密码\n");
      fgets(msg->data,100,stdin);  
       msg->data[strlen(msg->data)-1]='\0';
      
      if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
     {
       perror("历史失败");
       exit(-1);
     }

       if(recvfrom(fd,msg,sizeof(MSG),0,(struct sockaddr*)&saddr,&len)==-1)
       {
           perror("recv 失败");
           exit(-1);
       }
    
       printf("%s\n",msg->data);

}
void zhuxiao(int fd,MSG*msg,struct sockaddr_in saddr,int len){
       msg->type=12;
   printf("确认要注销账户?y/n\n");
            fgets(msg->data,100,stdin);
            msg->data[strlen(msg->data)-1]='\0'; 
      if(strcmp(msg->data,"n")==0){
         return;
      }
      else if(strcmp(msg->data,"y")==0){
      

      if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
     {
       perror("send error");
       exit(-1);
     }

       if(recvfrom(fd,msg,sizeof(MSG),0,(struct sockaddr*)&saddr,&len)==-1)
       {
           perror("recv error");
           exit(-1);
       }
       else{
       printf("%s\n",msg->data);
       return;
      }  
    }
      else{
     printf("输入有误\n");
      }

}


//五子棋
//打印棋盘


//初始化棋盘
void Initmap(char map[ROWS][COLS],int row, int col)
{
    memset(map,' ',row*col*sizeof(char));
}



void Printmap(char map[ROWS][COLS],int row,int col)
{
    int  i = 0;
    printf("\033[0m    1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10\n");
    for(; i < row;i++)
    {
        printf("%2d ",i+1);
        int j = 0;
        for(; j < col;j++)
        {
            if( j == col-1 )
            {
                printf(" %c \n",map[i][j]);
                if(i != row-1)
                    printf("   ---|---|---|---|---|---|---|---|---|---\n");
                break;
            }
            printf(" %c ",map[i][j]);
            printf("|");
        }
    }
}

//判断棋盘是否满了
int IsFall(char map[ROWS][COLS])
{
    size_t i = 0;
    for(; i < ROWS;i++)
    {
        size_t j = 0;
        for(; j < COLS; j++)
        {
            if(map[i][j] == ' ')
                return 0;
        }
    }
    return 1;
}
//移动
void CommonMove(char map[ROWS][COLS],MSG* msg,char ch)
{
    if(msg == NULL)
    {
        return;
    }
    int x = msg->row;
    int y = msg->col;
    //如果棋盘满了的话就退出循环,也就是不能再下子了
    while(1)
    {
        if(x >= 0 && x < ROWS && y >= 0 && y < COLS){
            if(map[x][y] == ' ')
            {
                map[x][y] = ch;
                msg->row = x;
                msg->col = y;
                break;
            }
            else
            {
                printf("坐标输入有误,请重新输入坐标: ");
                scanf("%d%d",&x,&y);
                x--;
                y--;
            }
        }
        else{
            printf("坐标输入有误,请重新输入坐标: ");
            scanf("%d%d",&x,&y);
            x--;
            y--;
        }
    }
}
//客户端移动
void Cli1Move(char map[ROWS][COLS],MSG* msg)
{
    CommonMove(map,msg,'@');
}

//服务器移动
void Cli2Move(char map[ROWS][COLS],MSG* msg)
{
    CommonMove(map,msg,'O');
}
//列齐
int ColState(char map[ROWS][COLS],MSG* msg)
{
    int x = msg->row;
    int y = msg->col;
    int count = 1;
    while(x-1 >= 0)
    {
        if(map[x][y] != map[x-1][y])
            break;
        count++;
        if(count == 5)
        {
            //如果往上遍历已经够了五个,说明已经赢了,直接返回
            return count;
        }
        x--;
    }
    //到这里说明当前点往上走是不满足条件的
    //但是已经走到了最上面的点,所以从临界点往相反方向找
    //必须要找到五个连续的才算满足条件
    count = 1;//count 重新被设定为1
    while(x+1 <= ROWS)
    {
        if(map[x][y] == map[x+1][y])
        {
            count++;
            if(count == 5)
            {
                return count;
            }
            x++;
        }
        else
        {
            //n 代表当前状态未满足赢的条件
            return 0;
        }
    }
    return 0;
}
//行齐
int RowState(char map[ROWS][COLS],MSG* msg)
{
    int x = msg->row;
    int y = msg->col;
    int count = 1;
    while(y-1 >= 0)
    {
        if(map[x][y] != map[x][y-1])
            break;
        count++;
        if(count == 5)
        {
            //如果往左遍历已经够了五个,说明已经赢了,直接返回
            return count;
        }
        y--;
    }
    //到这里说明当前点往左走是不满足条件的
    //但是已经走到了最左面的点,所以从临界点往相反方向找
    //必须要找到五个连续的才算满足条件
    count = 1;//count 重新被设定为1
    while(y+1 <= COLS)
    {
        if(map[x][y] == map[x][y+1])
        {
            count++;
            if(count == 5)
            {
                return count;
            }
            y++;
        }
        else
        {
            //n 代表当前状态未满足赢的条件
            return 0;
        }
    }
    return 0;
}
//左上到右下的对角线
int UpLeftState(char map[ROWS][COLS],MSG* msg)
{
    int x = msg->row;
    int y = msg->col;
    int count = 1;
    while(x-1 >= 0 && y-1 >= 0 )
    {
        if(map[x][y] != map[x-1][y-1])
            break;
        count++;
        if(count == 5)
        {
            //如果往左上遍历已经够了五个,说明已经赢了,直接返回
            return count;
        }
        x--;
        y--;
    }
    //到这里说明当前点往左上走是不满足条件的
    //但是已经走到了最左上的点,所以从临界点往相反方向找
    //必须要找到五个连续的才算满足条件
    count = 1;//count 重新被设定为1
    while(x+1 <= ROWS && y+1 <= COLS)
    {
        if(map[x][y] == map[x+1][y+1])
        {
            count++;
            if(count == 5)
            {
                return count;
            }
            x++;
            y++;
        }
        else
        {
            //n 代表当前状态未满足赢的条件
            return 0;
        }
    }
    return 0;
}
//右上到左下的对角线
int UpRightState(char map[ROWS][COLS], MSG* msg)
{
    int x = msg->row;
    int y = msg->col;
    int count = 1;
    while(x-1 >= 0 && y+1 <= COLS)
    {
        if(map[x][y] != map[x-1][y+1])
            break;
        count++;
        if(count == 5)
        {
            //如果往右上遍历已经够了五个,说明已经赢了,直接返回
            return count;
        }
        x--;
        y++;
    }
    //到这里说明当前点往右上走是不满足条件的
    //但是已经走到了最右上面的点,所以从临界点往相反方向找
    //必须要找到五个连续的才算满足条件
    count = 1;//count 重新被设定为1
    while(x+1 <= ROWS && y-1 <=COLS)
    {
        if(map[x][y] == map[x+1][y-1])
        {
            count++;
            if(count == 5)
            {
                return count;
            }
            x++;
            y--;
        }
        else
        {
            //n 代表当前状态未满足赢的条件
            return 0;
        }
    }
    return 0;
}
//返回游戏进行状态
char GameState(char map[ROWS][COLS],MSG* msg)
{
    if(msg == NULL)
    {
        return 'e';
    }
    //判断当前点所在列是否是连续五个子儿
    if(ColState(map,msg) == 5)
    {
        return map[msg->row][msg->col];
    }
    //判断当前点所在行是否是连续五个子儿
    else if(RowState(map,msg) == 5)
    {
        return map[msg->row][msg->col];
    }
    //判断当前点所在左上与右下的对角线是否满足条件
    else if(UpLeftState(map,msg) == 5)
    {
        return map[msg->row][msg->col];
    }
    //判断当前点所在左上与右下的对角线是否满足条件
    else if(UpRightState(map,msg) == 5)
    {
        return map[msg->row][msg->col];
    }
    else if(IsFall(map))
    {
        //平局
        return 'p'; 
    }
    //当前没有输赢,继续游戏
    return 'g';
}


void Game(int fd,MSG*msg,struct sockaddr_in saddr,int len,int flag)
{
    msg->type=14;

    char map[ROWS][COLS];
    TP tp;
    Initmap(map,ROWS,COLS);
    Printmap(map,ROWS,COLS);
    int x,y=0;

    if(flag==1){

        while(1){
            msg->row=0;
            msg->col=0;

            printf("你是先手请下子@(输入坐标)> ");

            scanf("%d%d",&x,&y);
            getchar();


            msg->row = x-1;
            msg->col = y-1;

            Cli1Move(map,msg);
            Printmap(map,ROWS,COLS);

            if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
            {
                perror("send error");
                exit(-1);
            }

            if(GameState(map,msg) == '@')
            {
                printf("你赢啦!\n");
                break;
            }
            else if(GameState(map,msg) == 'p')
            {
                printf("平局!\n");
                break;
            }

            printf("等待对方输入... \n");

            if(recvfrom(fd,&tp,sizeof(TP),0,(struct sockaddr*)&saddr,&len)==-1)
            {
                perror("recv 失败");
                exit(-1);
            }
            msg->row=tp.row;
            msg->col=tp.col;

            Cli2Move(map,msg);
            Printmap(map,ROWS,COLS);
            if(GameState(map,msg) == 'O')
            {
                printf("你输啦!\n");
                break;
            }
            else if(GameState(map,msg) == 'p')
            {
                printf("平局!\n");
                break;
            }

        }


    }

    else if(flag==2) {


        while(1){
            msg->row=0;
            msg->col=0;

            printf("你是后手等待对方输入... \n");

            if(recvfrom(fd,&tp,sizeof(TP),0,(struct sockaddr*)&saddr,&len)==-1)
            {
                perror("recv 失败");
                exit(-1);
            }

            msg->row=tp.row;
            msg->col=tp.col;


            printf("收到服务器消息\n");    
            Cli1Move(map,msg);
            Printmap(map,ROWS,COLS);

            if(GameState(map,msg) == '@')
            {
                printf("你输啦!\n");
                break;
            }
            else if(GameState(map,msg) == 'p')
            {
                printf("平局!\n");
                break;
            }

            printf("到你下棋了请下子O(输入坐标)> ");
            scanf("%d%d",&x,&y);
            getchar();

            msg->row = x-1;
            msg->col = y-1;

            Cli2Move(map,msg);
            Printmap(map,ROWS,COLS);


            if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr * )&saddr,len)==-1)
            {
                perror("send error");
                exit(-1);
            }
            if(GameState(map,msg) == 'O')
            {
                printf("你赢啦!\n");
                break;
            }
            else if(GameState(map,msg) == 'p')
            {
                printf("平局!\n");
                break;
            }
        }
    }
    else{
        printf("房间已满\n");
    }

}
int f=-1;

void shunxu(int fd,MSG*msg,struct sockaddr_in seraddr,int len){
    msg->type=13;

    if(sendto(fd,msg,sizeof(MSG),0,(struct sockaddr *)&seraddr,len)==-1)
    {
        perror("send error");
        exit(-1);
    }
    if(recvfrom(fd,msg,sizeof(MSG),0,(struct sockaddr*)&seraddr,&len)==-1)
    {
        perror("recv 失败");
        exit(-1);
    }

    f=msg->flag;
    printf("%s\n",msg->data);
}

void chat_menu(int fd,MSG*msg,struct sockaddr_in saddr,int len){
    int  n;
    while(1) {
        printf("\033[1;35m🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈\n");
      //  printf("\033[1;31m登陆成功!你来啦! %s  !\n",msg->name);
        printf("\033[1;31m        使用功能      \n");
        printf("\033[1;36m1 .加入群聊  \033[1;33m2 .聊天记录\n");
        printf("\033[1;34m3 .加入悄悄话\033[1;32m4 .电子字典\n");
        printf("\033[1;36m5 .查字典记录\033[1;33m6 .服务器目录\n");
        printf("\033[1;34m7 .上传文件  \033[1;32m8 .下载文件\n");
        printf("\033[1;31m9 .修改密码  \033[1;37m10.注销账号\n");
        printf("\033[1;32m11.下棋顺序  \033[1;34m12.双人五子棋\n");
        printf("\033[1;31m13.退出\n");
        printf("\033[1;35m🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈\n");

        int sc=scanf("%d",&n);
        if(sc==-1){
            perror("scanf\n");
            exit(-1);
        }
        getchar();
        switch(n)
        {
            case 1:
                chat(fd,msg,saddr,len);
                break;
            case 2:
                history(fd,msg,saddr,len);
                break;
            case 3:
                siliao(fd,msg,saddr,len);
                break;
            case 4:
                zidian(fd,msg,saddr,len);
                break;
            case 5:
                zidianhis(fd,msg,saddr,len);
                break;
            case 6:
                mulu(fd,msg,saddr,len);
                break;
            case 7:
                scwj(fd,msg,saddr,len);
                break;
            case 8:
                xzwj(fd,msg,saddr,len);
                break;
            case 9:
                gaipass(fd,msg,saddr,len);
                return;
            case 10:
                zhuxiao(fd,msg,saddr,len);
                return;
            case 11:
                 shunxu(fd,msg,saddr,len);
                break;
            case 12:
                 Game(fd,msg,saddr,len,f);
                break;

            case 13:
                printf("\033[1;36m感谢使用,欢迎下次再来\n");
                close(fd);
                exit(0);
                return;

            default:
                printf("\033[1;31m输入错误\n");
                break;
        }
    }
    return;
}

int main(int argc, const char *argv[]){
    //入参合理性检查
    if(3 != argc){
        printf("Usage : %s <IP> <PORT>\n", argv[0]);
        exit(-1);
    }

    show_connect();


    //1.创建用户数据报套接字
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(-1 == fd){
        ERRLOG("socket error");
    }
    //2.填充服务器的网络信息结构体
    struct sockaddr_in seraddr;
    memset(&seraddr, 0, sizeof(seraddr));
    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(atoi(argv[2]));
    seraddr.sin_addr.s_addr = inet_addr(argv[1]);
    int len = sizeof(seraddr);

    int choose;
    while(1){
        MSG msg;    
        printf("\033[1;35m🌵🌵🌵🌵🌵🌵🌵🌵🌵🌵🌵🌵\n");
        printf("\033[1;33m      欢迎使用系统      \n");
        printf("\033[1;36m        选择功能        \n");
        printf("\033[1;31m1.注册   \033[1;35m2.登陆   \033[1;32m3.退出\n");
        printf("\033[1;35m🌵🌵🌵🌵🌵🌵🌵🌵🌵🌵🌵🌵\n");

        int sc=scanf("%d",&choose);
        if(sc==-1){
            perror("scanf\n");
            exit(-1);
        }
        getchar();

        switch(choose)
        {
            case 1:
                zhuce(fd,&msg,seraddr,len);
                break;
            case 2:
                if(denglu(fd,&msg,seraddr,len)==1){
                    chat_menu(fd,&msg,seraddr,len);  
                }
                break;
            case 3:
                printf("\033[1;34m感谢使用,欢迎下次再来\n");
                close(fd);
                exit(0);
            default:
                printf("\033[1;34m输入错了请重新输入\n");
        }  
    }

    return 0;
}

运行结果:

;