电子词典多线程版本

前言:

这里涉及了多线程,使功能更加丰富

dict_server2.c

#include 
#include
#include
#include
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include
#include


//基于TCP通信,使用数据库完成电子词典功能
//服务端(实现一个服务端对多个客户端)


//登录管理
char* login(sqlite3* mydb,int socket_ok){

    char** resultp; //resultp里面存储了数据表中的所有数据
    int row; 
    int column;

    //接收账号
    char id[12];
    memset(id,0,sizeof(id));
    recv(socket_ok,id,sizeof(id),0);

    //接收密码
    char password[12];
    memset(password,0,sizeof(password));
    recv(socket_ok,password,sizeof(password),0);

    //接收名字
    char name2[12];
    memset(name2,0,sizeof(name2));
    recv(socket_ok,name2,sizeof(name2),0);


    char sql2[512];
    memset(sql2,0,sizeof(sql2));
    snprintf(sql2,sizeof(sql2),"select * from user where id = '%s' and password = '%s' and name = '%s'",id,password,name2);
    //执行sql
    sqlite3_get_table(mydb,sql2,&resultp,&row,&column,NULL);

    char resultStr[4096] = "";//存储结果集
    memset(resultStr,0,sizeof(resultStr));
    //拼接字符串
    for(int i=0;i<(row+1)*column;i++)//(row+1)这里加1,是因为没有把头算进去,我们要想输出头,就需要+1
    {
        
        strcat(resultStr, resultp[i]);//拼接字符串
        strcat(resultStr, "\t\t"); // 使用制表符分隔

        if((i+1)%column == 0)//这里是换行,每当下标i取模列为0的时候换行
        {
            strcat(resultStr, "\n");//换行
        }
    }
    //发送数据
    send(socket_ok,resultStr,sizeof(resultStr),0);
    
    memset(sql2,0,sizeof(sql2));

    //返回用户名字
    char* name = malloc(12*sizeof(char));
    strcpy(name,name2);
    return name;

}

//注册管理
void user_register(sqlite3* mydb,int socket_ok){

    char** resultp;
    int row; 
    int column;

    //接收账号
    char id[12];
    memset(id,0,sizeof(id));
    recv(socket_ok,id,sizeof(id),0);

    //接收账号
    char password[12];
    memset(password,0,sizeof(password));
    recv(socket_ok,password,sizeof(password),0);

    //接收名字
    char name[12];
    memset(name,0,sizeof(name));
    recv(socket_ok,name,sizeof(name),0);


    //首先检查账号合不合法
    char sql2[128] = "select * from user;";
    sqlite3_get_table(mydb,sql2,&resultp,&row,&column,NULL);

    for(int i=0;i<(row+1)*column;i++){

        if(strcmp(id,resultp[i])==0){//账号重复,非法
            char msg[12] = "-1";
            send(socket_ok,msg,strlen(msg),0);
            return;
        }
    }

    //到这里账号合法
    char sql[512];
    memset(sql,0,sizeof(sql));
    snprintf(sql,sizeof(sql),"insert into user(id,password,name)values('%s','%s','%s')",id,password,name);
    //执行sql
    sqlite3_get_table(mydb,sql,&resultp,&row,&column,NULL);
    char msg2[12] = "1";
    send(socket_ok,msg2,strlen(msg2),0);
    memset(sql,0,sizeof(sql));

}

//记录查询单词
void history(sqlite3* mydb,char str1[],char str2[],char name[]){

    char** resultp;
    int row; 
    int column;

    //拼接sql
    char sql[512];
    memset(sql,0,sizeof(sql));
    snprintf(sql,sizeof(sql),"insert into history(name,word,explain)values('%s','%s','%s');",name,str1,str2);
    printf("%s\n",sql);
    sqlite3_get_table(mydb,sql,&resultp,&row,&column,NULL);

    memset(sql,0,sizeof(sql));
}

//字典功能
void dict(sqlite3* mydb,int socket_ok,char name[]){

    //首先读出字典的数据
    //使用标准io打开字典文件
    FILE* fp = fopen("./dict.txt","r");
    if(fp==NULL){
        perror("open dict.txt failed");
        return;
    }

    //接收查询的单词
    char msg[30];
    memset(msg,0,sizeof(msg));
    recv(socket_ok,msg,sizeof(msg),0);
    printf("查询%s\n",msg);

    
    char buf[1024];//存储一行数据
    memset(buf,0,sizeof(buf));
    char msg2[1024];//存储单词解释

    //feof 函数用于检查文件流的文件结束标志。如果 feof(fp) 返回 0(假),
    //表示文件流 fp 还没有到达文件的末尾,如果返回非零值(真),表示文件流 fp 已经到达文件的末尾。
    while(fgets(buf,sizeof(buf),fp)!=NULL && !feof(fp)){//确保读到了文件尾

        //这里为了避免记录单词查询记录时出错,我们把buf最后的回车符去掉
        size_t ret = strcspn(buf,"\n");// 使用strcspn函数找到回车符的位置
        // 如果找到回车符,则将其替换为字符串结束符'\0'
        if (buf[ret] == '\n') {
            buf[ret] = '\0';
        }
        
        char dest[25];//存储读出来的单词
        memset(dest,0,sizeof(dest));//清0
        //sscanf 函数在提取数据时是以空白字符(例如空格、制表符、换行符等)作为分隔符的。当你使用 "%s" 格式指定来提取一个字符串时
        //,sscanf 会从输入字符串 input 中找到第一个非空白字符,然后开始提取字符,直到再次遇到空白字符为止。
        sscanf(buf,"%s",dest);//观察字典文件可知,只需要拷贝前17个字节中的单词部分

        if( strcmp(msg,dest) == 0 ){//匹配查询的单词
            memset(msg2,0,sizeof(msg2));
            strcpy(msg2,&buf[17]);//从第18个字节开始一直到最后,就是单词的解释
            send(socket_ok,msg2,strlen(msg2),0);

            history(mydb,msg,msg2,name);//记录查询

            return;
        }

        memset(buf,0,sizeof(buf));

    }


    //程序到这里说明没有找到单词
    char msg3[64] = "-1";
    send(socket_ok,msg3,strlen(msg3),0);
    fclose(fp);
}

//查看单词查询记录
void dict_history(sqlite3* mydb,int socket_ok,char name[]){

    //操作数据库,执行特定的sql语句
    char sql[512];
    memset(sql,0,sizeof(sql));
    snprintf(sql,sizeof(sql),"select * from history where name = '%s';",name);
    printf("%s\n",sql);

    //操作数据库
    char** resultp; //resultp里面存储了数据表中的所有数据
    int row; 
    int column;
    sqlite3_get_table(mydb,sql,&resultp,&row,&column,NULL);

    char resultStr[4096] = "";//存储结果集
    memset(resultStr,0,sizeof(resultStr));
    //拼接字符串
    for(int i=0;i<(row+1)*column;i++)//(row+1)这里加1,是因为没有把头算进去,我们要想输出头,就需要+1
    {
        
        strcat(resultStr, resultp[i]);//拼接字符串
        strcat(resultStr, "\t\t"); // 使用制表符分隔

        if((i+1)%column == 0)//这里是换行,每当下标i取模列为0的时候换行
        {
            strcat(resultStr, "\n");//换行
        }
    }

    //发送数据
    send(socket_ok,resultStr,sizeof(resultStr),0);

    memset(sql,0,sizeof(sql));
}


//收藏单词
void shoucang_word(sqlite3* mydb,int socket_ok,char name[]){

    //操作数据库
    char** resultp; 
    int row; 
    int column;

    //接收要收藏的单词
    char word[12];
    memset(word,0,sizeof(word));
    recv(socket_ok,word,sizeof(word),0);
   
    //操作数据库,执行特定的sql语句
    char sql[512];
    memset(sql,0,sizeof(sql));
    snprintf(sql,sizeof(sql),"insert into shoucang(name,word)values('%s','%s')",name,word);
    printf("%s\n",sql);
    sqlite3_get_table(mydb,sql,&resultp,&row,&column,NULL);

    //返回
    char msg[12]="1";
    send(socket_ok,msg,sizeof(msg),0);

    memset(sql,0,sizeof(sql));
}

//查看收藏的单词
void sel_shoucnag(sqlite3* mydb,int socket_ok,char name[]){

    //操作数据库
    char** resultp; 
    int row; 
    int column;
    
    //操作数据库,执行特定的sql语句
    char sql[512];
    memset(sql,0,sizeof(sql));
    snprintf(sql,sizeof(sql),"select distinct shoucang.*,history.explain from shoucang,history where shoucang.word = history.word and shoucang.name='%s';",name);
    printf("%s\n",sql);
    sqlite3_get_table(mydb,sql,&resultp,&row,&column,NULL);

    char resultStr[4096] = "";//存储结果集
    memset(resultStr,0,sizeof(resultStr));
    //拼接字符串
    for(int i=0;i<(row+1)*column;i++)//(row+1)这里加1,是因为没有把头算进去,我们要想输出头,就需要+1
    {
        
        strcat(resultStr, resultp[i]);//拼接字符串
        strcat(resultStr, "\t\t"); // 使用制表符分隔

        if((i+1)%column == 0)//这里是换行,每当下标i取模列为0的时候换行
        {
            strcat(resultStr, "\n");//换行
        }
    }

    //发送数据
    send(socket_ok,resultStr,sizeof(resultStr),0);
    
    memset(sql,0,sizeof(sql));
}


//删除收藏的单词
void del_shoucang(sqlite3* mydb,int socket_ok,char name[]){
    //操作数据库
    char** resultp; 
    int row; 
    int column;
    
    //先查询所有收藏的单词
    char sql2[128];
    //拼接字符串
    snprintf(sql2,sizeof(sql2),"select * from shoucang where name = '%s';",name);
    sqlite3_get_table(mydb,sql2,&resultp,&row,&column,NULL);

    char resultStr[4096] = "";//存储结果集
    memset(resultStr,0,sizeof(resultStr));
    //拼接字符串
    for(int i=0;i<(row+1)*column;i++)//(row+1)这里加1,是因为没有把头算进去,我们要想输出头,就需要+1
    {
        
        strcat(resultStr, resultp[i]);//拼接字符串
        strcat(resultStr, "\t\t"); // 使用制表符分隔

        if((i+1)%column == 0)//这里是换行,每当下标i取模列为0的时候换行
        {
            strcat(resultStr, "\n");//换行
        }
    }
    //发送数据
    send(socket_ok,resultStr,sizeof(resultStr),0);

    //接收要删除的单词
    char del_word[12];
    memset(del_word,0,sizeof(del_word));
    recv(socket_ok,del_word,sizeof(del_word),0);

    //拼接字符串
    char sql[512];
    memset(sql,0,sizeof(sql));
    snprintf(sql,sizeof(sql),"delete from shoucang where word = '%s'and name = '%s';",del_word,name);
    printf("%s\n",sql);
    sqlite3_get_table(mydb,sql,&resultp,&row,&column,NULL);
    //返回
    char msg[12]="1";
    send(socket_ok,msg,sizeof(msg),0);
    
    memset(sql,0,sizeof(sql));

}


//线程函数
void* jieshou(void* arg){

    //取出每个客户端对应的套接字
    int socket_ok2 = *((int *)arg);

    //打开数据库
    sqlite3* mydb = NULL; 
    int ret = sqlite3_open("./dict.db",&mydb);
    if(ret==-1){
        perror("open failed");
        exit(0);
    }

    char name[12];//存储当前登录人的名字

    //在这里执行匹配逻辑
    char buf[128];
    while(1){

        //5.接收客户端发来的操作标志
        memset(buf,0,sizeof(buf));

        recv(socket_ok2,buf,sizeof(buf),0);//阻塞等待,接收操作标志位
        printf("服务端接收到 %s 号操作\n",buf);

        int input = atoi(buf);

        switch (input)
        {
        case 1:
            strcpy(name,login(mydb,socket_ok2));//注意这里接收了登录时用户的名字
            break;
        case 2:
            user_register(mydb,socket_ok2);
            break;
        case 3:
            dict(mydb,socket_ok2,name);
            break;
        case 4:
            dict_history(mydb,socket_ok2,name);
            break;
        case 5:
            shoucang_word(mydb,socket_ok2,name);
            break;
        case 6:
            sel_shoucnag(mydb,socket_ok2,name);
            break;
        case 7:
            del_shoucang(mydb,socket_ok2,name);
            break;
        case 0:
            exit(0);
            break;
        
        default:
            printf("输入错误,请重新输入\n");
            break;
        }

    }

    close(socket_ok2);

}

int main(int argc,char** argv)
{

    //1. 创建套接字
    int socket_fd = socket(AF_INET,SOCK_STREAM,0);
    if(socket_fd == -1){
        printf("创建套接字失败\n");
        return -1;
    }

    //2. 绑定套接字与服务端网络地址
    struct sockaddr_in s_addr;
    s_addr.sin_family = AF_INET;
    s_addr.sin_port = htons(atoi(argv[2]));
    s_addr.sin_addr.s_addr = inet_addr(argv[1]);
    //绑定
    int bind_ok = bind(socket_fd,(struct sockaddr*)&s_addr,sizeof(s_addr));
    if(bind_ok==-1){
        perror("bind failed");
    }

    //3. 设置监听
    int socket_listen = listen(socket_fd,4);

    
    

    while(1){//在这个死循环里循环等待,对端发来的请求,来一个我就开一个线程

        //4.等待对端连接
        printf("等待连接\n");
        struct sockaddr_in c_addr;//保存客户端地址信息
        socklen_t size_len = sizeof(c_addr);
        int socket_ok = accept(socket_fd,(struct sockaddr*)&c_addr,&size_len);
        if(socket_ok==-1){
            perror("连接失败\n");
            return -1;
        }
        printf("连接成功\n");
        //定义线程号
        pthread_t tid;

        pthread_create(&tid,NULL,&jieshou&socket_ok);

    }

    close(socket_fd);

    return 0;
}

dict_client2.c

#include 
#include
#include
#include
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include
#include


//基于TCP通信,使用数据库完成学生信息管理系统,并增加电子词典功能
//客户端

int socket_fd = -1;
char result[4096];

//登录管理
int login(){

    //发送操作标志位
    char buf[12] = "1";
    send(socket_fd,buf,sizeof(buf),0);

    char id[12];
    printf("请输入4位账号:");
    scanf("%s",id);
    //发送账号
    send(socket_fd,id,strlen(id),0);

    char password[12];
    printf("请输入3位密码:");
    scanf("%s",password);
    //发送密码
    send(socket_fd,password,strlen(password),0);

    char name[12];
    printf("请输入你的姓名:");
    scanf("%s",name);
    send(socket_fd,name,strlen(name),0);


    //接收消息
    memset(result,0,sizeof(result));
    recv(socket_fd,result,sizeof(result),0);//阻塞等待

    if(result[0] != '\0'){//有账号且密码正确
        return 1;
    }else{//无账号或账号密码错误
        return -1;
    }

}

//注册管理
void user_register(){

    //发送操作标志位
    char buf[12] = "2";
    send(socket_fd,buf,sizeof(buf),0);

    char id[12];
    printf("请输入4位账号:");
    scanf("%s",id);
    send(socket_fd,id,strlen(id),0);

    char password[12];
    printf("请输入3位密码:");
    scanf("%s",password);
    send(socket_fd,password,strlen(password),0);

    char name[12];
    printf("请输入你的姓名:");
    scanf("%s",name);
    send(socket_fd,name,strlen(name),0);

    //接收消息
    memset(result,0,sizeof(result));
    recv(socket_fd,result,sizeof(result),0);//阻塞等待

    if(strcmp(result,"1")==0){//注册成功
        printf("账号注册成功\n");
    }else if(strcmp(result,"-1")==0){//账号非法
        printf("账号重复,请重新输入\n");
    }
}

//退出
void quit(){
    //发送操作标志位
    char buf[12] = "0";
    send(socket_fd,buf,sizeof(buf),0);

}


//收藏单词
void shoucang_word(char word[]){
    //发送操作标志位
    char buf[12] = "5";
    send(socket_fd,buf,sizeof(buf),0);

    //发送给收藏的单词给服务端
    send(socket_fd,word,strlen(word),0);

    //接收结果
    memset(result,0,sizeof(result));
    recv(socket_fd,result,sizeof(result),0);
    if(strcmp(result,"1")==0){
        printf("收藏成功\n");
    }else{
        printf("收藏失败\n");
    }

}

//字典功能
void dict(){

    //发送操作标志位
    char buf[12] = "3";
    send(socket_fd,buf,sizeof(buf),0);

    char search[30];
    printf("请输入你要查询的单词:");
    scanf("%s",search);
    //发送给服务端查询
    send(socket_fd,search,strlen(search),0);

    //接收查询结果
    //接收消息
    memset(result,0,sizeof(result));
    recv(socket_fd,result,sizeof(result),0);
    if(strcmp(result,"-1")==0){
        printf("抱歉你的输入有误  或者  本词典没有收录此单词\n");
    }else{//查询成功
        printf("%s\n",result);

        printf("\n");

        //只有查询成功,才有收藏的机会
        char input[12];
        memset(input,0,sizeof(input));
        printf("是否收藏此单词(yes/no)?");
        scanf("%s",input);
        if(strcmp(input,"yes")==0){
            //调用收藏函数
            shoucang_word(search);
        }

    }
    
}

//查看单词查询记录
void dict_history(){
    //发送操作标志位
    char buf[128] = "4";
    send(socket_fd,buf,sizeof(buf),0);

    //接收消息
    memset(result,0,sizeof(result));
    recv(socket_fd,result,sizeof(result),0);//阻塞等待

    if(result[0] != '\0'){
        printf("%s\n",result);
    }else{
        printf("查询失败\n");
    }
}

//查看收藏的单词
void sel_shoucnag(){
    //发送操作标志位
    char buf[128] = "6";
    send(socket_fd,buf,sizeof(buf),0);

    //接收消息
    memset(result,0,sizeof(result));
    recv(socket_fd,result,sizeof(result),0);//阻塞等待
    if(result[0] != '\0'){
        printf("%s\n",result);
    }else{
        printf("查询失败\n");
    }
    
}

//删除收藏的单词
void del_shoucang(){
    //发送操作标志位
    char buf[128] = "7";
    send(socket_fd,buf,sizeof(buf),0);

    //接收所有收藏的单词数据,供用户选择
    //接收消息
    memset(result,0,sizeof(result));
    recv(socket_fd,result,sizeof(result),0);//阻塞等待
    if(result[0] != '\0'){
        printf("%s\n",result);

        char del_word[30];
        printf("请输入要删除的单词:");
        scanf("%s",del_word);
        send(socket_fd,del_word,strlen(del_word),0);

        //接收消息
        memset(result,0,sizeof(result));
        recv(socket_fd,result,sizeof(result),0);//阻塞等待
        if(result[0] != '\0'){
            printf("删除成功\n");
        }else{
            printf("删除失败\n");
        }

    }else{
        printf("查询失败\n");
    }

    


    //接收消息

}

void menu(){
    printf("*********************************************************\n");
    printf("****      1. dict                2. dict_history     ****\n");
    printf("****      3. sel_shoucnag        4. del_shoucang     ****\n");
    printf("****                    0. exit                      ****\n");
    printf("*********************************************************\n");
}

void menu2(){
    printf("*********************************************************\n");
    printf("****       1.login                     2.register    ****\n");
    printf("*********************************************************\n");
}

void caidan(){
    int input;
    do{

        printf("\n");
        sleep(1);
        menu();
        printf("请输入你的操作:");
        scanf("%d",&input);

        switch (input)
        {
        case 1:
            dict();
            break;
        case 2:
            dict_history();
            break;
        case 3:
            sel_shoucnag();
            break;
        case 4:
            del_shoucang();
            break;
        case 0:
            quit();
            break;
        
        default:
            printf("输入错误,请重新输入\n");
            break;
        }

    }while(input);
}

int main(int argc,char** argv)
{
    
    //1. 创建套接字
    socket_fd = socket(AF_INET,SOCK_STREAM,0);
    if(socket_fd == -1){
        printf("创建套接字失败\n");
        return -1;
    }

    //2.初始化服务端网络地址
    struct sockaddr_in s_addr;
    s_addr.sin_family = AF_INET;
    s_addr.sin_port = htons(atoi(argv[2]));
    s_addr.sin_addr.s_addr = inet_addr(argv[1]);
    
    //3. 请求连接
    connect(socket_fd,(struct sockaddr*)&s_addr,sizeof(s_addr));

    //先登录
    int in;
    do{
        printf("\n");
        sleep(1);
        menu2();
        printf("请输入你的操作:");
        scanf("%d",&in);
        int ret = -1;
        switch (in)
        {
        case 1:
            ret = login();
            if(ret==1){
                printf("登录成功\n");
                caidan();
                exit(0);
            }else if(ret == -1){
                printf("账号或者密码错误\n");
            }
            break;
        case 2:
            user_register();
            break;
        default:
            printf("输入错误,请重新选择\n");
            break;
        }
    }while(in);


    close(socket_fd);
    return 0;
}

电子词典多线程版本_第1张图片

你可能感兴趣的:(Sqlite,数据库,sqlite,linux,c语言,tcp/ip,线程)