项目需求

  1. 登录注册功能
  2. 单词查询功能
  3. 历史记录功能
  4. 支持多客户端连接
  5. 采用数据库保存用户信息与历史记录
  6. 将dict.txt的数据导入到数据库中保存

开发步骤

1.流程图(一个大致的思路和想法)

2.根据流程图写框架(像做填空题一样,先写出题目,后去填充)

3.逐步实现每个功能(会发现流程图中的错误,回过头去补充完善)

最初的流程图

功能实现后修改完善的流程图

服务器

#include <stdio.h>
#include <string.h>
#include <sqlite3.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <sys/select.h>
//3个table名
#define USR "usr"
#define DICT "dict"
#define RECORD "record"
//size定义
#define SQLLEN 100
#define SIZE 150    //词典一行字符串读取长度限制
#define EN 50        //英文字符串长度限制
#define CN 100        //中文字符串长度限制
#define TYPLEN 20
#define USRLEM 20
#define PWDLEN 20
#define HISLEM 80
#define DATLEN 30
#define ERR_LOG(errmsg) do{\
    perror(errmsg);\
    fprintf(stderr,"%d %s %s\n",__LINE__,__func__,__FILE__);\
}while(0)
typedef struct protocol{
    char type[TYPLEN];
    char usrname[USRLEM];
    char passwd[PWDLEN];
    char en[EN];
    char zh_CN[CN];
    char history[HISLEM];
}DATAFRAME;
//函数定义
int create_table(sqlite3* db,char* sql);//创建一个表
int get_all_table(sqlite3* db,char* table_name,int isprintf);//查询表中全部数据,可选择是否打印
int insert_alldict(sqlite3* db);//导入词典到数据库中的dict表
//select name from table_name where name="usrname";
int select_usr_intable(sqlite3* db,char* value,int isprintf);
//select en from dict where en="xxxxx";
int select_en_intable(sqlite3* db,char* value,int isprintf);
//select en from dict where en="xxxxx";
char* select_zh_intable(sqlite3* db,char* value,int isprintf);
//select column1, column2 from table_name where column1="value1" and column2="value2";
int select_pwd_sta_intable(sqlite3* db,char* table_name,char* column1,char* column2,char* value1,char* value2,int isprintf);
//select time, record ,name from history where name="xxxxx";
int select_history_intable(sqlite3* db,char* value,int isprintf);
void get_history(sqlite3* db,char* value);
int insert_usr(sqlite3* db,char* value1,char* value2,char* value3);//增加用户数据到表
int insert_history(sqlite3* db,char* value1,char* value2,char* value3);//增加查词记录数据到表history
int update_usrstate(sqlite3* db,char* name,char* state);//修改用户状态
int update_allusrstate(sqlite3* db);//启动,初始化全部用户状态state="0"
int update_maxfd(int maxfd,fd_set readfds);//更新maxfd
char* get_time(char* date);//获取当前日期和时间
//全局变量
char** all_result;//全部历史记录
char** send_result;//全部历史记录
int send_k=0;
int send_row=0;//行
int send_column=0;//列
int main(int argc, char const *argv[])
{
    if(argc < 3)
    {
        printf("请输入本地IP号和端口号\n");
        return 0;
    }   
    //创建(打开)一个数据库
    sqlite3* db = NULL;
    char* errmsg = NULL;
    if(sqlite3_open("./dictionary.db",&db) != SQLITE_OK)
    {
        fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
        return -1; 
    }
    printf("数据库打开(创建)成功\n");
    //创建(打开)3个表
    char sql[SQLLEN] = "create table if not exists usr(name char primary key,passwd char,state char);";
    if(create_table(db,sql) < 0)
    {
        fprintf(stderr,"%d %s %s\n",__LINE__,__func__,"打开(创建)表usr失败");
    }
    printf("表usr打开(创建)成功\n");
    bzero(sql,SQLLEN);
    strcpy(sql,"create table if not exists dict(en char,zh_CN char);");
    if(create_table(db,sql) < 0)
    {
        fprintf(stderr,"%d %s %s\n",__LINE__,__func__,"打开(创建)表dict失败");
    }  
    printf("表dict打开(创建)成功\n"); 
    bzero(sql,SQLLEN);
    strcpy(sql,"create table if not exists history(time char,record char,name char);");
    if(create_table(db,sql) < 0)
    {
        fprintf(stderr,"%d %s %s\n",__LINE__,__func__,"打开(创建)表history失败");
    }  
    printf("表history打开(创建)成功\n");
    //启动,初始化全部用户状态state="0"
    update_allusrstate(db); 
    //如果表dict为空,重新导入原始词典数据
    int dict_row = get_all_table(db,DICT,0);
    printf("表dict单词数:%d\n",dict_row);
    if(dict_row == 0)
    {
        insert_alldict(db);
        printf("词典导入数据库成功\n");
        printf("表dict单词数:%d\n",get_all_table(db,DICT,0));
    }
    //socket套接字
    int sfd = socket(AF_INET,SOCK_STREAM,0);
    if(sfd < 0)
    {
        ERR_LOG("socket");
        return -1;
    }
    //端口快速重用
    int reuse = 1;
    if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(int)) < 0)
    {
        ERR_LOG("setsockopt");
        return -1;
    }
    //bind
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(*(unsigned short*)argv[2]);
    saddr.sin_addr.s_addr = inet_addr(argv[1]);
    if(bind(sfd,(struct sockaddr*)&saddr,sizeof(saddr)) < 0)
    {
        ERR_LOG("bind");
        return -1;
    }
    //listen
    if(listen(sfd,5) < 0)
    {
        ERR_LOG("listen");
        return -1;
    }
    //变量定义
    DATAFRAME buf = {{0},{0},{0},{0},{0},{0}};
    struct sockaddr_in caddr;
    socklen_t caddrlen = sizeof(caddr);
    fd_set readfds,tempfds;
    FD_ZERO(&readfds);
    FD_ZERO(&tempfds);
    FD_SET(sfd,&readfds);
    int maxfd = 0;
    maxfd = sfd;
    int cfd,recv_len,i;
    char date[DATLEN] = "";
    printf("服务器启动成功,等待客户端连接\n");
    while(1)
    {
        tempfds = readfds;
        int selret = select(maxfd+1,&tempfds,NULL,NULL,NULL);
        if(selret <= 0)
        {
            ERR_LOG("select");
            return -1;
        }
        for(i=0;i<=maxfd;i++)
        {
            if(!FD_ISSET(i,&tempfds))
            {
                continue;
            }
            if(i == sfd)//accept连接事件
            {
                cfd = accept(sfd,(struct sockaddr*)&caddr,&caddrlen);
                if(cfd < 0)
                {
                    ERR_LOG("accept");
                    return -1;
                }
                printf("有新客户端连接成功\n");
                FD_SET(cfd,&readfds);
                maxfd = maxfd>cfd ? maxfd : cfd;
            }
            else if(i > 3)//客户端交互事件
            {
                bzero(buf.type,TYPLEN);
                recv_len = recv(i,&buf,sizeof(DATAFRAME),0);  
                if(recv_len < 0)
                {
                    ERR_LOG("recv");
                    return -1;
                }
                else if(0 == recv_len)
                {
                    //printf("fd = %d的客户端断开连接\n",i);//test
                    close(i);
                    FD_CLR(i,&readfds);
                    //更新maxfd
                    maxfd = update_maxfd(maxfd,readfds);  
                }   
                else
                {
                    printf("%s 收到来自[%s:%d]客户端的请求信息:%s\n",get_time(date),inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port),buf.type);
                    //注册请求
                    if(memcmp("register",buf.type,sizeof("register")) == 0)
                    {
                        //查询用户是否注册
                        // select name from usr where name="xxxxx";
                        if(select_usr_intable(db,buf.usrname,1) == 0)//未注册
                        {
                            //增加用户
                            if(insert_usr(db,buf.usrname,buf.passwd,"0") == 0)
                            {
                                printf("%s 新增用户%s到表usr成功\n",get_time(date),buf.usrname);
                            }
                            else
                                printf("新增用户失败\n");
                            bzero(buf.type,TYPLEN);
                            strcpy(buf.type,"success");
                            if(send(i,&buf,sizeof(DATAFRAME),0) < 0)
                            {
                                ERR_LOG("send");
                                return -1;
                            }
                        }
                        else//已注册
                        {
                            bzero(buf.type,TYPLEN);
                            strcpy(buf.type,"repeat");
                            if(send(i,&buf,sizeof(DATAFRAME),0) < 0)
                            {
                                ERR_LOG("send");
                                return -1;
                            }
                        }
                    }
                    //登录请求
                    else if(memcmp("login",buf.type,sizeof("login")) == 0)
                    {
                        //查询用户是否存在
                        // select name from usr where name="xxxxx";
                        if(select_usr_intable(db,buf.usrname,1) == 0)//不存在
                        {
                            bzero(buf.type,TYPLEN);
                            strcpy(buf.type,"nulluser");
                            if(send(i,&buf,sizeof(DATAFRAME),0) < 0)
                            {
                                ERR_LOG("send");
                                return -1;
                            }
                        }
                        else//用户已存在
                        {  
                            //查询密码是否正确
                            //select name, passwd from usr where name="xxxx" and passwd="xxxxx";
                            if(select_pwd_sta_intable(db,USR,"name","passwd",buf.usrname,buf.passwd,1) == 0)//密码不正确
                            {
                                printf("%s 用户%s尝试登录,密码错误\n",get_time(date),buf.usrname);
                                bzero(buf.type,TYPLEN);
                                strcpy(buf.type,"passwderr");
                                if(send(i,&buf,sizeof(DATAFRAME),0) < 0)
                                {
                                    ERR_LOG("send");
                                    return -1;
                                }  
                            }
                            else//密码正确
                            {
                                //查询用户是否已登录
                                //select name, state from usr where name="xxxx" and state="xxxxx";
                                if(select_pwd_sta_intable(db,USR,"name","state",buf.usrname,"0",1) == 0)//用户已登录
                                {
                                    printf("%s 用户%s重复登录请求,已拒绝\n",get_time(date),buf.usrname);
                                    bzero(buf.type,TYPLEN);
                                    strcpy(buf.type,"relogin");
                                    if(send(i,&buf,sizeof(DATAFRAME),0) < 0)
                                    {
                                        ERR_LOG("send");
                                        return -1;
                                    }   
                                }
                                else//用户未登录,允许登录
                                {
                                    //修改用户状态state="1"
                                    update_usrstate(db,buf.usrname,"1");
                                    printf("%s 用户%s上线了\n",get_time(date),buf.usrname);
                                    bzero(buf.type,TYPLEN);
                                    strcpy(buf.type,"allowlogin");
                                    if(send(i,&buf,sizeof(DATAFRAME),0) < 0)
                                    {
                                        ERR_LOG("send");
                                        return -1;
                                    }  
                                }
                            }
                        }
                    }
                    //查单词请求
                    else if(memcmp("en",buf.type,sizeof("en")) == 0)
                    {
                        //插入历史记录
                        char hdate[DATLEN] = "";
                        strcpy(hdate,get_time(date));
                        if(insert_history(db,hdate,buf.en,buf.usrname) == 0)
                        {
                            printf("%s 新增查词记录%s %s到表history成功\n",get_time(date),date,buf.en);
                        }
                        else
                            printf("新增历史记录失败\n");  
                        //查询英文是否存在
                        //select en from dict where en="xxxxx";
                        if(select_en_intable(db,buf.en,1) == 0)//不存在
                        {
                            bzero(buf.type,TYPLEN);
                            strcpy(buf.type,"noen");
                            if(send(i,&buf,sizeof(DATAFRAME),0) < 0)
                            {
                                ERR_LOG("send");
                                return -1;
                            }
                        }
                        else//存在
                        {
                            bzero(buf.zh_CN,CN);
                            //获取中文
                            strcpy(buf.zh_CN,select_zh_intable(db,buf.en,0));
                            bzero(buf.type,TYPLEN);
                            strcpy(buf.type,"zh");
                            if(send(i,&buf,sizeof(DATAFRAME),0) < 0)
                            {
                                ERR_LOG("send");
                                return -1;
                            }   
                        }
                    }
                    //查历史记录请求
                    else if(memcmp("history",buf.type,sizeof("history")) == 0)
                    {
                        //查找属于用户的历史记录
                        if(select_history_intable(db,buf.usrname,1) == 0)//没有历史记录
                        {
                            bzero(buf.type,TYPLEN);
                            strcpy(buf.type,"nohistory");
                            if(send(i,&buf,sizeof(DATAFRAME),0) < 0)
                            {
                                ERR_LOG("send");
                                return -1;
                            }  
                        }
                        else//有历史查询记录
                        {
                            send_k = 0;
                            get_history(db,buf.usrname);
                            send_result = all_result+3;
                            int m=0,n=0;
                            for(m=0;m<send_row;m++)
                            {
                                bzero(buf.history,HISLEM);
                                for(n=0;n<send_column;n++)
                                {
                                    if(n == send_column-1)
                                    {
                                        break;
                                    }
                                    else if(n == 0)
                                    {
                                        strcpy(buf.history,send_result[send_k]);
                                        //printf("n=%d,%s",n,send_result[send_k]);//test
                                    }
                                    else if(n == 1)
                                    {
                                        strcat(buf.history," ");
                                        strcat(buf.history,send_result[send_k]);
                                        //printf("n=%d,%s",n,send_result[send_k]);//test
                                    }
                                    send_k++;
                                }
                                putchar(10);
                                send_k++;
                                bzero(buf.type,TYPLEN);
                                strcpy(buf.type,"continue");
                                if(send(i,&buf,sizeof(DATAFRAME),0) < 0)
                                {
                                    ERR_LOG("send");
                                    return -1;
                                } 
                            }
                            bzero(buf.type,TYPLEN);
                            strcpy(buf.type,"finish");
                            if(send(i,&buf,sizeof(DATAFRAME),0) < 0)
                            {
                                ERR_LOG("send");
                                return -1;
                            }  
                        }
                    }  
                    //退出登录请求
                    else if(memcmp("logout",buf.type,sizeof("logout")) == 0)
                    {
                        //修改用户状态state="0"
                        update_usrstate(db,buf.usrname,"0");
                        printf("%s 用户%s下线了\n",get_time(date),buf.usrname);
                        bzero(buf.type,TYPLEN);
                        strcpy(buf.type,"allowlogout");
                        if(send(i,&buf,sizeof(DATAFRAME),0) < 0)
                        {
                            ERR_LOG("send");
                            return -1;
                        } 
                    }   
                    else if(memcmp("signallogout",buf.type,sizeof("signallogout")) == 0)
                    {
                        //中断退出,修改用户状态state="0"
                        update_usrstate(db,buf.usrname,"0");
                        printf("%s 用户%s下线了\n",get_time(date),buf.usrname);
                    }  
                }
            }
        }
    }
    close(sfd);
    //关闭数据库
    sqlite3_close(db);
    printf("数据库已关闭\n");
    return 0;
}
//创建一个表
int create_table(sqlite3* db,char* sql)
{
    char* errmsg = NULL;
     if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK)
    {
        fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
        return -1;
    }   
    return 0;
}
//查询表中全部数据,可选择是否打印
int get_all_table(sqlite3* db,char* table_name,int isprintf)
{
    char sql[SQLLEN] = "";
    sprintf(sql,"select * from %s;",table_name);
    char** result = NULL;
    int row = 0,column = 0;
    char* errmsg = NULL;
    if(sqlite3_get_table(db,sql,&result,&row,&column,&errmsg) != SQLITE_OK)
    {
        fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
        return -1;
    }
    int i=0,j=0,k=0;
    if(isprintf)
    {
        for(i=0;i<=row;i++)//行 = 字符段1行 + 记录段row行
        {
            for(j=0;j<column;j++)//列
            {
                printf("%-10s\t",result[k]);
                k++;
            }
            putchar(10);
        }
    }
    return row;
}
//导入词典到数据库中的dict表
int insert_alldict(sqlite3* db)
{
    char sql[SQLLEN] = "";
     //打开词典
    FILE *fp = fopen("./dict.txt","r");
    if(fp == NULL)
    {
        ERR_LOG("fopen");
        return -1;
    }
    char word[SIZE] = "";
    while(fgets(word,SIZE,fp) != NULL)
    {
        //拆分中英文
        char en[EN]="",zh_CN[CN]="";
        int en_len=0,ch_len=0;
        char *p=word;
        while(*p!=' ')
        {
            p++;
            en_len++;
        }
        strncpy(en,word,en_len);//得到英文
        while(*p==' ')p++;
        char *c=p;
        while(*p!='\0')
        {
            p++;
            ch_len++;
        }
        strncpy(zh_CN,c,ch_len);//得到释义中文
        bzero(sql,SQLLEN);
        sprintf(sql,"insert into dict values(\"%s\",\"%s\");",en,zh_CN);
        char *errmsg = NULL;
        if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK)
        {
            fprintf(stderr,"%d %s %s en_word:%s\n",__LINE__,__func__,errmsg,en);
            return -1;
        }
    }   
    fclose(fp);
    return 0;
}
//存在返回1,不存在返回0
//isprintf==1,打印查询的结果
//select name from usr where name="usrname";
int select_usr_intable(sqlite3* db,char* value,int isprintf)
{
    char sql[SQLLEN] = "";
    //select name from usr where name="sheng";
    sprintf(sql,"select name from usr where name=\"%s\";",value);
    char** result;
    int row,column;
    char* errmsg = NULL;
    if(sqlite3_get_table(db,sql,&result,&row,&column,&errmsg) != SQLITE_OK)
    {
        fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
        return -1;
    }
    int i=0,j=0,k=0;
    if(isprintf)
    {
        printf("_____________________________\n");
        printf("select_usr_intable:\n");
        for(i=0;i<=row;i++)//行 = 字符段1行 + 记录段row行
        {
            for(j=0;j<column;j++)//列
            {
                printf("%-10s\t",result[k]);
                k++;
            }
            putchar(10);
        }
        printf("_____________________________\n");
    }
    return row;
}
//select en from dict where en="xxxxx";
int select_en_intable(sqlite3* db,char* value,int isprintf)
{
    char sql[SQLLEN] = "";
    //select en from dict where en="xxxxx";
    sprintf(sql,"select en from dict where en=\"%s\";",value);
    char** result;
    int row,column;
    char* errmsg = NULL;
    if(sqlite3_get_table(db,sql,&result,&row,&column,&errmsg) != SQLITE_OK)
    {
        fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
        return -1;
    }
    int i=0,j=0,k=0;
    if(isprintf)
    {
        printf("_____________________________\n");
        printf("select_en_intable:\n");
        for(i=0;i<=row;i++)//行 = 字符段1行 + 记录段row行
        {
            for(j=0;j<column;j++)//列
            {
                printf("%-10s\t",result[k]);
                k++;
            }
            putchar(10);
        }
        printf("_____________________________\n");
    }
    return row;
}
//获取中文
//select en from dict where en="xxxxx";
char* select_zh_intable(sqlite3* db,char* value,int isprintf)
{
    char sql[SQLLEN] = "";
    //select en, zh_CN from dict where en="xxxxx";
    sprintf(sql,"select en, zh_CN from dict where en=\"%s\";",value);
    char** result;
    int row,column;
    char* errmsg = NULL;
    if(sqlite3_get_table(db,sql,&result,&row,&column,&errmsg) != SQLITE_OK)
    {
        fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
        return NULL;
    }
    int i=0,j=0,k=0;
    if(isprintf)
    {
        printf("_____________________________\n");
        printf("select_zh_intable:\n");
        for(i=0;i<=row;i++)//行 = 字符段1行 + 记录段row行
        {
            for(j=0;j<column;j++)//列
            {
                printf("%-10s\t",result[k]);
                k++;
            }
            putchar(10);
        }
        printf("_____________________________\n");
    }
    return result[3];
}
//select time, record ,name from history where name="xxxxx";
int select_history_intable(sqlite3* db,char* value,int isprintf)
{
    char sql[SQLLEN] = "";
    //select time, record ,name from history where name="xxxxx";
    int row,column;
    char** result;
    sprintf(sql,"select time, record ,name from history where name=\"%s\";",value);
    char* errmsg = NULL;
    if(sqlite3_get_table(db,sql,&result,&row,&column,&errmsg) != SQLITE_OK)
    {
        fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
        return -1;
    }
    int i=0,j=0,k=0;
    if(isprintf)
    {
        printf("_____________________________\n");
        printf("select_history_intable:\n");
        for(i=0;i<=row;i++)//行 = 字符段1行 + 记录段row行
        {
            for(j=0;j<column;j++)//列
            {
                printf("%-20s\t",result[k]);
                k++;
            }
            putchar(10);
        }
        printf("_____________________________\n");
    }
    return row;
}
//select time, record ,name from history where name="xxxxx";
void get_history(sqlite3* db,char* value)
{
    char sql[SQLLEN] = "";
    //select time, name from history where name="xxxxx";
    sprintf(sql,"select time, record ,name from history where name=\"%s\";",value);
    char* errmsg = NULL;
    if(sqlite3_get_table(db,sql,&all_result,&send_row,&send_column,&errmsg) != SQLITE_OK)
    {
        fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
        return;
    }
}
//select column1, column2 from table_name where column1="value1" and column2="value2";
int select_pwd_sta_intable(sqlite3* db,char* table_name,char* column1,char* column2,char* value1,char* value2,int isprintf)
{
    char sql[SQLLEN] = "";
    sprintf(sql,"select %s, %s from %s where %s=\"%s\" and %s=\"%s\";",column1,column2,table_name,column1,value1,column2,value2);
    char** result;
    int row,column;
    char* errmsg = NULL;
    if(sqlite3_get_table(db,sql,&result,&row,&column,&errmsg) != SQLITE_OK)
    {
        fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
        return -1;
    }
    int i=0,j=0,k=0;
    if(isprintf)
    {
        printf("_____________________________\n");
        printf("select_pwd_sta_intable:\n");
        for(i=0;i<=row;i++)//行 = 字符段1行 + 记录段row行
        {
            for(j=0;j<column;j++)//列
            {
                printf("%-10s\t",result[k]);
                k++;
            }
            putchar(10);
        }
        printf("_____________________________\n");
    }
    return row;
}
//修改用户状态
int update_usrstate(sqlite3* db,char* name,char* state)
{
    char sql[SQLLEN] = "";
    sprintf(sql,"update usr set state=\"%s\" where name=\"%s\";",state,name);
    char *errmsg = NULL;
    if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK)
    {
        fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
        return -1;
    }
    return 0;
}
//启动,初始化全部用户状态state="0"
int update_allusrstate(sqlite3* db)
{
    char sql[SQLLEN] = "";
    sprintf(sql,"update usr set state=\"0\";");
    char *errmsg = NULL;
    if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK)
    {
        fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
        return -1;
    }
    return 0;
}
//增加用户数据到表usr
int insert_usr(sqlite3* db,char* value1,char* value2,char* value3)
{
    char sql[SQLLEN] = "";
    sprintf(sql,"insert into usr values(\"%s\",\"%s\",\"%s\");",value1,value2,value3);
    char *errmsg = NULL;
    if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK)
    {
        fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
        return -1;
    }
    return 0;
}
//增加查词记录数据到表history
int insert_history(sqlite3* db,char* value1,char* value2,char* value3)
{
    char sql[SQLLEN] = "";
    sprintf(sql,"insert into history values(\"%s\",\"%s\",\"%s\");",value1,value2,value3);
    char *errmsg = NULL;
    if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK)
    {
        fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
        return -1;
    }
    return 0;
}
//更新maxfd
int update_maxfd(int maxfd,fd_set readfds)
{
    int i;
    for(i=maxfd;i>=0;i--)
    {
        if(FD_ISSET(i,&readfds))
        {
            return i;
        }
    }
    return 0;
}
//获取当前日期和时间
char* get_time(char* date)
{
    time_t t;
    time(&t); 
    struct tm *tm = localtime(&t);
    strftime(date,DATLEN,"[%Y-%m-%d %H:%M:%S]",tm); 
    return date;
}

客户端

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <signal.h>
//size定义
#define EN 50      
#define CN 100
#define TYPLEN 20
#define USRLEM 20
#define PWDLEN 20
#define HISLEM 80
#define ERR_LOG(errmsg) do{\
    perror(errmsg);\
    fprintf(stderr,"%d %s %s\n",__LINE__,__func__,__FILE__);\
}while(0)
typedef struct protocol{
    char type[TYPLEN];
    char usrname[USRLEM];
    char passwd[PWDLEN];
    char en[EN];
    char zh_CN[CN];
    char history[HISLEM];
}DATAFRAME;
typedef struct arg{
    int sfd;
    DATAFRAME buf;
}ARG;
//全局变量
int sfd;
DATAFRAME buf = {{0},{0},{0},{0},{0},{0}};
int flag_inquiry,flag_logout;
//ctrl+c结束进程
typedef void (*sighandler_t)(int);
void handler_quit(int sig)
{
    bzero(buf.type,TYPLEN);
    strcpy(buf.type,"signallogout");
    if(send(sfd,&buf,sizeof(DATAFRAME),0) < 0)
    {
        ERR_LOG("send");
        return;
    }  
    putchar(10); 
    close(sfd);  
    exit(0);                                                                                          
}
//接收线程
void* handler_recv(void *arg)
{
    int* sfd = &((*(ARG*)arg).sfd);
    DATAFRAME* buf = &((*(ARG*)arg).buf);
    pthread_detach(pthread_self());
    int recv_len;
    while(1)
    {
        bzero(buf->type,TYPLEN);
        recv_len = recv(*sfd,buf,sizeof(DATAFRAME),0);
        if(recv_len < 0)
        {
            ERR_LOG("recv");
            return NULL;
        }
        else if(0 == recv_len)
        {
            printf("服务器关闭,退出\n");
            close(*sfd);
            exit(1);
        }
        else
        {
            if(memcmp("success",buf->type,sizeof("success")) == 0)
            {
                printf("**注册成功(按回车继续)\n");
            }
            else if(memcmp("repeat",buf->type,sizeof("repeat")) == 0)
            {
                printf("**该用户名已注册,请换个用户名重新注册(按回车继续)\n");
            }
            else if(memcmp("nulluser",buf->type,sizeof("nulluser")) == 0)
            {
                printf("**用户不存在,请注册用户后登录(按回车继续)\n");
            }      
            else if(memcmp("passwderr",buf->type,sizeof("passwderr")) == 0)
            {
                printf("**密码错误,请重新登录(按回车继续)\n");
            }
            else if(memcmp("relogin",buf->type,sizeof("relogin")) == 0)
            {
                printf("**该用户已登录,请勿重复登录(按回车继续)\n");
            }  
            else if(memcmp("allowlogin",buf->type,sizeof("allowlogin")) == 0)
            {
                flag_inquiry = 1;
                printf("**登录成功(按回车继续)\n");
            } 
            else if(memcmp("noen",buf->type,sizeof("noen")) == 0)
            {
                printf(">>抱歉,词典中没有这个英文单词,请重新输入(按回车继续)\n");
            }     
            else if(memcmp("zh",buf->type,sizeof("zh")) == 0)
            {
                //输出中文
                printf(">>%s\n",buf->zh_CN);
                printf("(按回车继续)\n");
            } 
            else if(memcmp("nohistory",buf->type,sizeof("nohistory")) == 0)
            {
                printf(">>没有查词历史记录,请查词(按回车继续)\n");
            } 
            else if(memcmp("continue",buf->type,sizeof("continue")) == 0)
            {
                printf(">>%s\n",buf->history);
            } 
            else if(memcmp("finish",buf->type,sizeof("finish")) == 0)
            {
                printf(">>查词历史记录打印完毕(按回车继续)\n");
            } 
            else if(memcmp("allowlogout",buf->type,sizeof("allowlogout")) == 0)
            {
                flag_logout = 1;
                printf("(按回车继续)\n");
            } 
        }
    }
    pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
    if(argc < 3)
    {
        printf("请输入服务器IP号和端口号\n");
        return 0;
    }
    //注册SIGINT信号 
    sighandler_t s; 
    s = signal(SIGINT, handler_quit); 
    if(s == SIG_ERR) 
    { 
        ERR_LOG("signal"); 
        return -1; 
    }
    //创建socket套接字
    sfd = socket(AF_INET,SOCK_STREAM,0);
    if(sfd < 0)
    {
        ERR_LOG("socket");
        return -1;
    }
    //connect连接服务端
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(*(unsigned short*)argv[2]);
    saddr.sin_addr.s_addr = inet_addr(argv[1]);
    if(connect(sfd,(struct sockaddr*)&saddr,sizeof(saddr)) < 0)
    {
        ERR_LOG("connect");
        return -1;
    }
    //printf("连接成功\n");//test
    //变量定义
    ARG arg = {sfd,buf};
    char option;
    flag_inquiry = 0;
    flag_logout = 0;
    //创建发送数据线程
    pthread_t tid;
    if(pthread_create(&tid,NULL,handler_recv,(void*)&arg) != 0)
    {
        ERR_LOG("pthread_creat");
        return -1;
    }
    //发送数据主线程
    while(1)
    {
        //用户登录界面
        system("clear");
        printf("****************************\n");
        printf("**1.注册   2.登录   3.退出**\n");
        printf("****************************\n");  
        printf("**请输入选项-->");
        scanf("%c",&option);
        getchar();
        switch(option)
        {
            case '1'://注册
                bzero(buf.usrname,USRLEM);
                printf("**请输入注册名-->");
                fgets(buf.usrname,USRLEM,stdin);
                buf.usrname[strlen(buf.usrname)-1] = 0;
                bzero(buf.passwd,PWDLEN);
                printf("**输入注册密码-->");
                fgets(buf.passwd,PWDLEN,stdin);
                buf.passwd[strlen(buf.passwd)-1] = 0;
                bzero(buf.type,TYPLEN);
                strcpy(buf.type,"register");
                 if(send(sfd,&buf,sizeof(DATAFRAME),0) < 0)
                {
                    ERR_LOG("send");
                    return -1;
                }   
                while(getchar()!=10);  
            break;
            case '2'://登录
                bzero(buf.usrname,USRLEM);
                printf("**请输入登录名-->");
                fgets(buf.usrname,USRLEM,stdin);
                buf.usrname[strlen(buf.usrname)-1] = 0;
                bzero(buf.passwd,PWDLEN);
                printf("**输入登录密码-->");
                fgets(buf.passwd,PWDLEN,stdin);
                buf.passwd[strlen(buf.passwd)-1] = 0;
                bzero(buf.type,TYPLEN);
                strcpy(buf.type,"login");
                 if(send(sfd,&buf,sizeof(DATAFRAME),0) < 0)
                {
                    ERR_LOG("send");
                    return -1;
                }   
                while(getchar()!=10); 
                if(flag_inquiry)
                {
                    goto INQUIRY;
                }
            break;
            case '3'://退出
                goto QUIT;
            break;
            default:
                printf("**输入选项错误,请输入提供的选项(按回车继续)");
                while(getchar()!=10);
            break;
        }
    }
INQUIRY:  
    while(1)
    {
        //用户查询界面
        system("clear");
        printf(">>>>>>>>>>>>>><<<<<<<<<<<<<<\n");
        printf(">>1.查词   2.历史   3.退出<<\n");
        printf(">>>>>>>>>>>>>><<<<<<<<<<<<<<\n");  
        printf(">>请输入选项-->");
        scanf("%c",&option);
        getchar();
        switch(option)  
        {
            case '1'://查单词
                bzero(buf.en,EN);
                printf(">>请输入要查询的英文单词-->");
                fgets(buf.en,EN,stdin);
                buf.en[strlen(buf.en)-1] = 0;
                bzero(buf.type,TYPLEN);
                strcpy(buf.type,"en");
                 if(send(sfd,&buf,sizeof(DATAFRAME),0) < 0)
                {
                    ERR_LOG("send");
                    return -1;
                }   
                while(getchar()!=10);      
            break;
            case '2'://查历史记录
                bzero(buf.type,TYPLEN);
                strcpy(buf.type,"history");
                 if(send(sfd,&buf,sizeof(DATAFRAME),0) < 0)
                {
                    ERR_LOG("send");
                    return -1;
                }   
                while(getchar()!=10);
            break;
            case '3'://退出登录
                bzero(buf.type,TYPLEN);
                strcpy(buf.type,"logout");
                 if(send(sfd,&buf,sizeof(DATAFRAME),0) < 0)
                {
                    ERR_LOG("send");
                    return -1;
                }   
                while(getchar()!=10);
                if(flag_logout)
                {
                    goto QUIT;
                }
            break;
            default:
                printf(">>输入选项错误,请输入提供的选项(按回车继续)");
                while(getchar()!=10);
            break;
        }  
    }
QUIT:
    printf("**退出成功\n");
    close(sfd);
    return 0;
}

演示

Last modification:2021 年 04 月 20 日 10 : 39 : 49