在线词典。
2021/7/25 23:50:39
本文主要是介绍在线词典。,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
在线词典实现框架:
1、在线词典
2、项目功能描述
3、用户注册和登录验证
4、服务器端将用户信息和历史记录保存在数据库中,客户端输入用户名和密码,服务器端在数据库中查找、匹配,返回结果
5、单次在线翻译
6、根据客户端输入的单次在字典文件中搜索
7、历史记录查询
8、项目分析
服务器流程图:
客户端流程图:
/*server*/ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <sqlite3.h> #include <signal.h> #include <time.h> #define N 128 #define R 1 //register #define L 2 //login #define O 3 //logout #define M 4 //modify #define Q 5 //query #define H 6 //history record #define DATABASE "my.db" typedef struct { int type; //类型 char name[N]; //用户名 char data[256]; //密钥 int flag; //标识位 }MSG; //客户端请求处理函数 int do_client(int rws, sqlite3 *db); //注册处理函数 int do_register(int rws, MSG *msg, sqlite3 *db); //登录处理函数 int do_login(int rws, MSG *msg, sqlite3 *db); //注销处理函数 int do_logout(int rws, MSG *msg, sqlite3 *db); //修改信息函数 int do_modify(int rws,MSG *msg,sqlite3 *db); //查询单词函数 int do_query(int rws,MSG *msg,sqlite3 *db); //显示查询记录函数 int do_record(int rws,MSG *msg,sqlite3 *db); // ./server 192.168.30.202 8888 int main(int argc, const char *argv[]) { int s = -1; //监听套接字 int rws =-1; //读写套接字 struct sockaddr_in addr; char *errmsg; pid_t pid; //命令行传参 if(argc != 3){ printf("Usage: %s <ipstr> <port>.\n", argv[0]); return -1; } //1.创建套接字 if((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket"); return -1; // exit(-1); } //2.初始化服务器端地址结构体 //bzero(&addr, sizeof(addr)); memset(&addr,0,sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr(argv[1]); addr.sin_port = htons(atoi(argv[2])); //3.绑定IP和端口 if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("bind"); goto ERR_STEP; //return -1; //exit(-1); } //4.监听套接字 if(listen(s, 10) < 0) { perror("listen"); goto ERR_STEP; //exit(-1); } //5.设置套接字端口复用属性 int on = 1; //setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { perror("setsockopt"); return -1; } //创建打开数据库 sqlite3 *db; if(sqlite3_open(DATABASE, &db) != SQLITE_OK) { printf("%s\n", sqlite3_errmsg(db)); return -1; } else { printf("open Database success\n"); } //需要在数据库中创建两张表:学生信息表和查询记录表 //创建学生信息表 //char sql[256]="create table if not exists stu(id integer primary key autoincrement, name text,passwd text);"; char sql[256]="create table if not exists stu(name text,passwd text);"; printf("sql=%s\n",sql);//调试信息 if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=0) { fprintf(stderr,"create table fail! %s\n",errmsg); return -1; } //创建历史记录信息表 char sql_history[256]="create table if not exists record(name text,datetime text,word text);"; printf("sql_history=:%s\n",sql_history);//调试信息 if(sqlite3_exec(db,sql_history,NULL,NULL,&errmsg)!=0) { fprintf(stderr,"create table fail! %s\n",errmsg); return -1; } printf("-------------------准备事项均已成功创建!-------------------------\n"); printf("-------------------接下来等待客户链接请求-------------------------\n"); //父进程接收子进程的退出信号 signal(SIGCHLD, SIG_IGN); //6.循环处理客户端的链接服务请求 while(1) { printf("wait for client...\n"); #if 0 /*如需打印连接的客户端信息,则开启此段代码*/ struct sockaddr_in cliaddr; socklen_t clilen=sizeof(cliaddr); rws=accept(s,(struct sockaddr*)&cliaddr,&clilen); //if(0 >(rws=accept(s,(struct sockaddr*)&cliaddr,&clilen)); char buf[INET_ADDRSTRLEN]={}; if(inet_ntop(AF_INET,&cliaddr.sin_addr.s_addr,buf,INET_ADDRSTRLEN)) { printf("client ip:%s ",buf); } printf("port:%u\n",ntohs(cusaddr.sin_port)); #endif #if 1 if((rws = accept(s, NULL, NULL)) < 0) { perror("accept"); exit(-1); } #endif //调用fork函数创建子进程 if((pid = fork()) < 0) { perror("fork"); exit(-1); } else if(pid == 0) { //子进程负责处理客户端发来的链接请求 close(s); //不需要监听套接字,关闭 do_client(rws, db); //处理函数,传参读写套接字以及数据库句柄 } else { //父进程负责接收客户请求 close(rws); //关闭读写套接字 } } ERR_STEP: close(s); close(rws); return 0; } //处理客户端请求函数 int do_client(int rws, sqlite3 *db) { MSG msg; //定义信息结构体变量 //客户端先发送链接请求信息 //服务器接收客户端的请求信息,并按照双方协议,判断客户端请求的类型 while(recv(rws, &msg, sizeof(msg), 0) > 0) { //根据结构体中请求类型变量,调用响应的子程序进行处理 switch(msg.type) { case R: do_register(rws, &msg, db); //注册,传参读写套接字,结构体地址,数据库句柄 break; case L: do_login(rws, &msg, db); //登录,传参读写套接字,结构体地址,数据库句柄 break; case O: do_logout(rws,&msg,db); //注销 break; case M: do_modify(rws,&msg,db); //修改 break; case Q: do_query(rws,&msg,db); //查询 break; case H: do_record(rws,&msg,db); //回查 break; default: //其他 printf("Invalid msg.\n"); break; } } printf("Client is leave...\n"); close(rws); exit(0); //退出时,发送SIGCHLD信号,父进程设置忽略处理 } //注册处理函数 int do_register(int rws, MSG *msg, sqlite3 *db) { char * errmsg; char sql[128]; //查重 //char *errmsg; int nrow, ncloumn; //数据库行数和列数 char **resultp; //定义二级指针保存SOL语句执行的结果 //拼接SOL语句,查询用户名和密码与数据库内容是否匹配 sprintf(sql, "select * from stu where name='%s';", msg->name); printf("%s\n", sql); //调试语句,打印SQL语句信息 //无回调函数版的,返回调用一个命令的整个结果集 if(sqlite3_get_table(db, sql, &resultp, &nrow, &ncloumn, &errmsg) != SQLITE_OK) { printf("%s\n", errmsg); return -1; } else { printf("get_table ok!\n"); } //调用传参行数,判断是否查找到用户信息,若有则代表已注册,否则可以注册 if(nrow == 1) { strcpy(msg->data, "REPEAT"); send(rws, msg, sizeof(MSG), 0); //发送匹配成功信息,证明有重复账号 return 1; } else { //拼接SQL语句,将客户端的姓名和密码加入添加到数据库 sprintf(sql, "insert into stu values('%s', %s);", msg->name, msg->data); printf("%s\n", sql); //调试语句,打印sql语句内容 if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)//便捷函数返回异常,代表注册失败,注册名已存在 { printf("%s\n", errmsg); strcpy(msg->data, "invaild input or stu name already exist."); //将注册错误信息填写至结构体信息成员,待返回客户端 } else { printf("client register ok!\n"); //成功 strcpy(msg->data, "ok!"); //成功信息填写至结构体信息成员,待返回客户端 } if(send(rws, msg, sizeof(MSG), 0) < 0) //发送信息至客户端,待客户反馈 { perror("send"); return -1; } } return 0; } //登录处理函数 int do_login(int rws, MSG *msg, sqlite3 *db) { char sql[128] = {}; char *errmsg; int nrow, ncloumn; //数据库行数和列数 char **resultp; //定义二级指针保存SOL语句执行的结果 //拼接SOL语句,查询用户名和密码与数据库内容是否匹配 sprintf(sql, "select * from stu where name='%s' and passwd='%s';", msg->name, msg->data); printf("%s\n", sql); //调试语句,打印SQL语句信息 //无回调函数版的,返回调用一个命令的整个结果集 if(sqlite3_get_table(db, sql, &resultp, &nrow, &ncloumn, &errmsg) != SQLITE_OK) { printf("%s\n", errmsg); return -1; } else { printf("get_table ok!\n"); } //调用传参行数,判断是否查找到用户信息,若有则代表成功,否则输入错误或用户不存在 if(nrow == 1) { strcpy(msg->data, "OK"); msg->flag=1; //登录成功,设置标识位为1 send(rws, msg, sizeof(MSG), 0); //发送匹配成功信息 return 1; } else { strcpy(msg->data, "usr/passwd wrong."); send(rws, msg, sizeof(MSG), 0); //发送匹配失败信息 } return 0; } //注销处理子函数 int do_logout(int rws, MSG *msg, sqlite3 *db) { char * errmsg; char sql[128]; //拼接SQL语句,以客户端登录姓名为关键字,从数据库中将整条信息删除 // sprintf(sql, "insert into usr values('%s', %s);", msg->name, msg->data); sprintf(sql, "delete from stu where name='%s';", msg->name); printf("%s\n", sql); //调试语句,打印sql语句内容 if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK) //便捷函数返回异常,代表注销失败 { printf("%s\n", errmsg); strcpy(msg->data, "stu name input error."); //将注销错误信息填写至结构体信息成员,待返回客户端 } else { printf("client logout ok!\n"); //成功 strcpy(msg->data, "ok!"); //成功注销信息,待返回客户端 } if(send(rws, msg, sizeof(MSG), 0) < 0) //发送信息至客户端,待客户反馈 { perror("send"); return -1; } return 0; } //修改信息子函数 int do_modify(int rws,MSG *msg,sqlite3 *db) { char * errmsg; char sql[128]; //拼接SQL语句,将要修改的内容内容传入SQL语句中 sprintf(sql,"update stu set passwd='%s' where name='%s';",msg->data,msg->name); printf("%s\n", sql);//调试语句,打印sql语句内容 if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK) //便捷函数返回异常,代表修改失败 { printf("%s\n", errmsg); strcpy(msg->data, "stu passwd modify fail."); //将修改未成功信息填写至结构体信息成员,待返回客户端 } else { printf("stu passwd modify ok!\n"); //成功 strcpy(msg->data, "ok!"); //成功信息填写至结构体信息成员,待返回客户端 } if(send(rws, msg, sizeof(MSG), 0) < 0) //发送信息至客户端,待客户反馈 { perror("send"); return -1; } return 0; } //查词函数(只负责查找,并返回查询函数结果,由查询函数最终向客户端反馈结果,查词成功还要向数据库插入数据) int do_searchword(int rws,MSG*msg,char *word) { //打开本地的词典文件,词典打开失败也要通知客户端 FILE* fp=fopen("./dict.txt","r"); if(NULL==fp) { perror("fopen failure"); strcpy(msg->data,"open dict.txt failure"); if(0 >send(rws,msg,sizeof(MSG),0)) { perror("send"); goto ERR_STEP; // return -1; } //打开成功,则需要比较词典中有无参数中的单词 } printf("word is %s,word len is %d\n",word,strlen(word));//调试信息 #define MAXSIZE 1024 char buf[MAXSIZE]={}; while(1) { while(fgets(buf,MAXSIZE,fp)) { int ret=strncmp(buf,word,strlen(word)); if(0 > ret) continue; //当前单词比要找单词小,继续 else if( 0 < ret) //当前单词比要找单词大,因为单词表是按ASCII码的顺序排序的,后面的单词ASCII更大,所以就是没找到 goto ERR_STEP; // return -1; else if((0==ret) && (buf[strlen(word)]!=' ')) //当前单词和要找单词在前n个字节一致,但词典中该词在长度n后面还有内容,也不是要找的内容 goto ERR_STEP; // return -1; else //除以上情况外,就是找到了,找打了就把名词解释发送给客户 { //此处难点是如何找到名词解释在哪里? //查看词典格式如下:abandonment n. abandoning //1.根据单词格式可以看出,名词解释的地址,就是在“单词+空格后的第一个非空字符”的地址 //2.所以应定义一个指针,最终可以指向这个地址 // ①跨过单词 // ②跨过空格 char *ptext; ptext=buf+strlen(word); while(*ptext==' ') ptext++; //正文复制到信息结构体中 strcpy(msg->data,ptext); printf("word find:%s",msg->data); //调试信息 goto ERR_STEP1; } } if(feof(fp)) break; } ERR_STEP1: fclose(fp); return 0; ERR_STEP: fclose(fp); return -1; } char* gettime() { time_t time_now; struct tm *t; time_now=time(NULL); t=localtime(&time_now); return asctime(t); } //查询单词函数 int do_query(int rws,MSG *msg,sqlite3 *db) { //接收客户端传来的单词 //检索该单词是否存在于本地文件或数据库中 //单词存在: //1.则从文件或数据库中取词,放到信息结构体中发送至客户端(关键) //2.把该单词和客户端姓名、查询时间信息放到数据库表record中(难点) //单词不存在,则发送“单词未找到信息反馈到客户端” //鉴于以上查询单词操作的分类情况和复杂度,应单独封装函数进行处理,用返回值区分单词存在还是不存在 //定义buf接收单词 char word[256]={}; char * errmsg; char time[256]={}; strcpy(word,msg->data); char sql_message[256]={}; int ret=do_searchword(rws,msg,word); if(0>ret) { //查询失败信息填入信息结构体 strcpy(msg->data,"This word cannot be found"); } else { //拼接,把查询记录添加到record数据表中 strcpy(time,gettime()); sprintf(sql_message,"insert into record values('%s','%s','%s');",msg->name,time,word); printf("sql_message:%s\n",sql_message); if(sqlite3_exec(db,sql_message,NULL,NULL,&errmsg)!=SQLITE_OK) { printf("%s\n", errmsg); strcpy(msg->data, "query success,buf server SQL entry failure"); //将查询信息录入失败信息填写至结构体信息成员,待返回客户端 } // return -1; } if(0 > send(rws,msg,sizeof(MSG),0)) { perror("send"); return -1; } printf("message:%s\n",msg->data); return 0; } //回调函数 int record_callback(void *para,int f_num,char **f_value,char **f_name) { int rws; MSG msg; rws=*(int *)para; sprintf(msg.data,"%s %s %s",f_value[0],f_value[1],f_value[2]); if(0 > send(rws,&msg,sizeof(MSG),0)) { perror("send"); return -1; } return 0; } //显示查询记录函数 int do_record(int rws,MSG *msg,sqlite3 *db) { char sql[256]={}; char *errmsg; sprintf(sql,"select *from record where name='%s';",msg->name); printf("sql=%s\n",sql); if(sqlite3_exec(db,sql,record_callback,(void*)&rws,&errmsg)!=SQLITE_OK) { printf("%s\n",errmsg); strcpy(msg->data, "History record query failure"); //将查询信息录入失败信息填写至结构体信息成员,待返回客户端 } else printf("query successful.\n"); msg->data[0]='\0'; if(0 > send(rws,msg,sizeof(MSG),0)) { perror("send"); return -1; } return 0; }
/*client*/ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #define N 128 //双方约定相同的信号定义 #define R 1 //register #define L 2 //login #define O 3 //logout #define M 4 //modify #define Q 5 //query #define H 6 //history recond typedef struct { int type; char name[N]; char data[256]; int flag; }MSG; //注册子函数 int do_register(int sockfd, MSG *msg) { //输入姓名 msg->type = R; printf("Input name:"); scanf("%s", msg->name); getchar(); //输入密码 printf("Input passwd:"); scanf("%s", msg->data); getchar(); //客户端先发送 if(send(sockfd, msg, sizeof(MSG), 0) < 0) { printf("fail to send.\n"); return -1; } //客户端后接收 if(recv(sockfd, msg, sizeof(MSG), 0) < 0) { printf("fail to recv.\n"); return -1; } //没有退出就是注册成功! //ok! or usr already exist. printf("%s\n", msg->data); return 0; } //登录子函数 int do_login(int sockfd, MSG *msg) { //输入姓名 msg->type = L; printf("Input name:"); scanf("%s", msg->name); getchar(); //输入密码 printf("Input passwd:"); scanf("%s", msg->data); getchar(); //发送登录信息 if(send(sockfd, msg, sizeof(MSG), 0) < 0) { printf("fail to send.\n"); return -1; } //接收服务器反馈 if(recv(sockfd, msg, sizeof(MSG), 0) < 0) { printf("fail to recv.\n"); return -1; } //返回ok代表登录成功 if(strncmp(msg->data, "OK", 3) == 0) { printf("Login OK!\n"); return 1; } //否则打印错误信息 else { printf("%s\n", msg->data); return 0; } return 0; } //注销子函数 int do_logout(int sockfd, MSG *msg) { if(msg->flag==0) { printf("Not logged in yet\n "); return -1; } //输入姓名 msg->type = O; #if 0 printf("Input name:"); scanf("%s", msg->name); getchar(); //输入密码 printf("Input passwd:"); scanf("%s", msg->data); #endif //客户端先发送 if(send(sockfd, msg, sizeof(MSG), 0) < 0) { printf("fail to send.\n"); return -1; } //客户端后接收 if(recv(sockfd, msg, sizeof(MSG), 0) < 0) { printf("fail to recv.\n"); return -1; } printf("%s\n", msg->data); return 0; } //修改子函数 int do_modify(int sockfd, MSG *msg) { if(msg->flag==0) { printf("Not logged in yet\n "); return -1; } msg->type = M; #if 0 printf("Input name:"); scanf("%s", msg->name); getchar(); #endif #if 1 //输入密码 printf("Input newpasswd:"); scanf("%s", msg->data); getchar(); #endif //客户端先发送 if(send(sockfd, msg, sizeof(MSG), 0) < 0) { printf("fail to send.\n"); return -1; } //客户端后接收 if(recv(sockfd, msg, sizeof(MSG), 0) < 0) { printf("fail to recv.\n"); return -1; } printf("%s\n", msg->data); return 0; } int do_query(int sockfd,MSG *msg) { msg->type=Q; while(1) { //输入要查询的单词,缓存接收单词 printf("please input a word:"); if(!fgets(msg->data,sizeof(msg->data)-1,stdin)) { printf("input error.\n"); return -1; } msg->data[strlen(msg->data)-1]='\0'; if(0==strncmp(msg->data,"&",1)) break; //通过套接字将单词传给客户端(先发) if(send(sockfd,msg,sizeof(MSG),0)<0) { printf("fail to send.\n"); return -1; } //接收服务器反馈,打印 if(recv(sockfd,msg,sizeof(MSG),0)<0) { printf("fail to recv.\n"); return -1; } printf("%s\n",msg->data); } return 0; } int do_recond(int sockfd,MSG*msg) { msg->type=H; if(send(sockfd,msg,sizeof(MSG),0) <0) { printf("fail to send.\n"); return -1; } while(1) { if(recv(sockfd,msg,sizeof(MSG),0)<0) { printf("fail to recv.\n"); return -1; } if(msg->data[0]==0) //按约定退出 break; printf("%s\n",msg->data); } return 0; } //./client 192.168.30.202 8888 int main(int argc, const char *argv[]) { int sockfd = -1; struct sockaddr_in sin; MSG msg; memset(&msg,0,sizeof(msg)); int n; //命令行传参 if(argc != 3){ printf("Usage: %s <servip> <port>.\n", argv[0]); return -1; } //1.创建套接字 if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ perror("socket"); exit(-1); } //2.初始化服务器地址结构体信息 bzero(&sin, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = inet_addr(argv[1]); sin.sin_port = htons(atoi(argv[2])); if(connect(sockfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { perror("connect"); exit(-1); } //循环向服务器端发送客户端链接请求,并把交互设计在客户端,服务器只是对客户端请求的应答 /* ----------------设计协议: 1.客户端请求:注册,登录,退出-----------------*/ next1: while(1) { printf("*****************************************\n"); printf("* 1:register 2.login 3:quit *\n"); printf("*****************************************\n"); printf("Please choose:");//选号,按号实现响应功能代码 char buf[256]={}; if(fgets(buf,256,stdin)) { int size=strlen(buf); printf("len=%d\n",size); // int num=buf[0]-'0'; // printf("num=%d\n",num); // buf[strlen(buf)-1]='\0'; if(strlen(buf)==2) { int num=buf[0]-'0'; printf("num=%d\n",num); if((!((num >= 1)&&(num <=3)))&&(strlen(buf)!='\n')) { printf("choose input Invalid,please enter again.\n"); continue; } } else { printf("choose input Invalid,please enter again.\n"); continue; } } #if 0 scanf("%d", &n); getchar(); //吃垃圾字符 if(!((n >= '1')&&(n <='3'))) { printf("choose input Invalid,please enter again.\n"); continue; } #endif switch(buf[0]-'0') { case 1: do_register(sockfd, &msg); //注册子函数 break; case 2: if(do_login(sockfd, &msg) == 1) //登录子函数 { goto next; } break; case 3: //退出子函数 close(sockfd); exit(0); break; default: //命令错误 printf("Invalid data cmd.\n"); } } next: while(1) { printf("**********************************************\n"); printf("* 1:logout 2:modify 3:return menu *\n"); printf("* 4:query 5:record *\n"); printf("**********************************************\n"); printf("Please choose:"); #if 1 char buf[256]={}; if(fgets(buf,256,stdin)) { int size=strlen(buf); printf("len=%d\n",size); // int num=buf[0]-'0'; // printf("num=%d\n",num); // buf[strlen(buf)-1]='\0'; if(strlen(buf)==2) { int num=buf[0]-'0'; printf("num=%d\n",num); if((!((num >= 1)&&(num <=5)))&&(strlen(buf)!='\n')) { printf("choose input Invalid,please enter again.\n"); continue; } } else { printf("choose input Invalid,please enter again.\n"); continue; } } #endif #if 0 scanf("%d", &n); getchar(); if(!((n >= '1')&&(n <='5'))) { printf("choose input Invalid,please enter again.\n"); continue; } #endif switch(buf[0]-'0'){ case 1: do_logout(sockfd, &msg); break; case 2: do_modify(sockfd,&msg); break; case 3: goto next1; // break; case 4: do_query(sockfd,&msg); break; case 5: do_recond(sockfd,&msg); break; default: printf("Invalid data cmd.\n"); } } return 0; }
希望看到此文章的小伙伴们,如果有什么错误,欢迎下方留言,博客肯定虚心接受并改正!大家一起共同进步。如果对你有所帮助,可以给博主一个小小的赞
这篇关于在线词典。的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-21《鸿蒙HarmonyOS应用开发从入门到精通(第2版)》简介
- 2024-12-21后台管理系统开发教程:新手入门全指南
- 2024-12-21后台开发教程:新手入门及实战指南
- 2024-12-21后台综合解决方案教程:新手入门指南
- 2024-12-21接口模块封装教程:新手必备指南
- 2024-12-21请求动作封装教程:新手必看指南
- 2024-12-21RBAC的权限教程:从入门到实践
- 2024-12-21登录鉴权实战:新手入门教程
- 2024-12-21动态权限实战入门指南
- 2024-12-21功能权限实战:新手入门指南