项目——电子词典(客户端、服务器交互,字典导入,单词查询)
一、项目要求
- 登录注册功能,不能重复登录,重复注册
- 单词查询功能
- 历史记录功能,存储单词,意思,以及查询时间
- 基于TCP,支持多客户端连接
- 采用数据库保存用户信息与历史记录
- 将dict.txt的数据导入到数据库中保存。
- 按下ctrl+c退出客户端后,注销该客户端的登录信息
二、主要实现功能
- 注册
- 登录
- 查询单词
- 查询历史记录
- 退出登录
三、框架设计
3.1 服务器
3.2 客户端
四、功能实现
4.1 服务器实现功能代码
4.1.1 导入词典
主要流程:
- 创建并打开数据库
- 创建数据表
- 打开词典所在目录文件
- 逐行读取并插入到数据表中
- 关闭文件描述符,关闭数据库
//导入词典
int import_dict(sqlite3 *db)
{if(sqlite3_open("./dict.db",&db) != SQLITE_OK){fprintf(stderr,"sqlite3_open: %s __%d__\n",sqlite3_errmsg(db),__LINE__);return -1;}//创建一个表char sql[128] = "create table if not exists dict (word char,mean char);";char *errmsg = NULL;if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK){fprintf(stderr,"sqlite3_exec: %s __%d__\n",errmsg,__LINE__);return -1;}//打开文件FILE* fp = fopen("./dict.txt", "r");if(NULL == fp){perror("fopen");return -1;}//循环读取文件中的数据,一行一行的读取char buf[256] = "";char word[32] = "";char mean[200] = "";int count = 1;int i = 0;char* ptr = NULL;printf("importing dictionary...\n");while(1){if(fgets(buf, sizeof(buf), fp) == NULL)break;buf[strlen(buf)-1] = 0;//分离单词和意思bzero(word, sizeof(word));bzero(mean, sizeof(mean));//获取" "子串在buf中的地址ptr = strstr(buf, " ");if(NULL == ptr){printf("没有找到对应子串\n");break;}strncpy(word, buf, ptr-buf); //" "子串前面是单词strcpy(mean, ptr+3); //" "子串后面是意思 //插入到数据库中sprintf(sql,"insert into dict values (\"%s\", \"%s\");", word, mean);if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){printf("sqlite3_exec failed:%s __%d__\n", errmsg, __LINE__);return -1;}}//关闭文件fclose(fp);//关闭数据库,释放对应的内存空间if(sqlite3_close(db) != SQLITE_OK){printf("sqlite3_close failed:%s __%d__\n", sqlite3_errmsg(db), __LINE__);return -1;}printf("dictionary import completed...\n");return 0;
}
4.1.2 注册
主要流程:
- 创建并打开数据库
- 创建数据表
- 匹配来自客户端的用户名,若存在,则回复用户名已存在;若不存在,则将用户名与密码插入数据表中
- 关闭数据库
//匹配用户名是否存在
int do_select_user(sqlite3 *db,char *name)
{char sql[128] = "select name from user;";char **pres = NULL;int row,column;char *errmsg = NULL;if(sqlite3_get_table(db,sql,&pres,&row,&column,&errmsg) != SQLITE_OK){fprintf(stderr,"sqlite3_exec: %s __%d__\n",errmsg,__LINE__);return -1;}for(int i=1;i<(row+1)*column;i++){if(strcmp(pres[i],name) == 0){fprintf(stderr,"sqlite3_exec: name already existss\n");return 1;}}return 0;
}
//实现注册功能
int Register(sqlite3 *db,char *buf)
{//打开数据库if(sqlite3_open("./dict.db",&db) != SQLITE_OK){fprintf(stderr,"sqlite3_open: %s __%d__\n",sqlite3_errmsg(db),__LINE__);return -1;}//创建一个表char sql[128] = "create table if not exists user (name char,passwd char);";char *errmsg = NULL;if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK){fprintf(stderr,"sqlite3_exec: %s __%d__\n",errmsg,__LINE__);return -1;}char *name = buf+2;char *passwd = buf+2+strlen(buf+2)+1;if(do_select_user(db,name) == 1){return 1;}sprintf(sql,"insert into user values ('%s','%s');",name,passwd);if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK){fprintf(stderr,"sqlite3_exec: %s __%d__\n",errmsg,__LINE__);return -1;}printf("register success...\n");//关闭数据库,释放对应的内存空间if(sqlite3_close(db) != SQLITE_OK){printf("sqlite3_close failed:%s __%d__\n", sqlite3_errmsg(db), __LINE__);return -1;}return 0;
}
4.1.3 登录
主要流程:
- 创建并打开数据库
- 创建数据表
- 匹配来自客户端的用户名和密码,若用户名和密码与数据库中的数据相匹配,则登录成功,否则登录失败
- 关闭数据库
//实现登录功能
int Login(sqlite3 *db,char *buf)
{//打开数据库if(sqlite3_open("./dict.db",&db) != SQLITE_OK){fprintf(stderr,"sqlite3_open: %s __%d__\n",sqlite3_errmsg(db),__LINE__);return -1;}char sql[128] = "create table if not exists user (name char,passwd char);";char *errmsg = NULL;if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK){fprintf(stderr,"sqlite3_exec: %s __%d__\n",errmsg,__LINE__);return -1;}strcpy(sql,"select * from user;");char **pres = NULL;int row,column;if(sqlite3_get_table(db,sql,&pres,&row,&column,&errmsg) != SQLITE_OK){fprintf(stderr,"sqlite3_exec: %s __%d__\n",errmsg,__LINE__);return -1;}char *name = buf+2;char *passwd = buf+2+strlen(buf+2)+1;for(int i=2;i<(row+1)*column;i++){if(strcmp(pres[i],name) == 0 && strcmp(pres[i+1],passwd) == 0){printf("login success...\n");if(sqlite3_close(db) != SQLITE_OK){printf("sqlite3_close failed:%s __%d__\n", sqlite3_errmsg(db), __LINE__);return -1;}return 2;}}//关闭数据库,释放对应的内存空间if(sqlite3_close(db) != SQLITE_OK){printf("sqlite3_close failed:%s __%d__\n", sqlite3_errmsg(db), __LINE__);return -1;}return 3;
}
4.1.4 查找单词
主要流程:
- 创建并打开数据库
- 创建数据表
- 匹配来自客户端的单词,若存在,则返回查询结果并将查询记录插入到数据表中,若不存在,则查询失败
- 关闭数据库
//插入记录
int Insert(sqlite3 *db,char *words,char *mean,char *save_buf)
{//获取当前时间time_t t;struct tm *info=NULL;char mytime[128] = "";t = time(NULL);info = localtime(&t);sprintf(mytime,"%d-%02d-%02d %02d:%02d:%02d",info->tm_year+1900,info->tm_mon+1,info->tm_mday,info->tm_hour,info->tm_min,info->tm_sec);//打开数据库if(sqlite3_open("./dict.db",&db) != SQLITE_OK){fprintf(stderr,"sqlite3_open: %s __%d__\n",sqlite3_errmsg(db),__LINE__);return -1;}//创建一个表char sql[128] = "create table if not exists history (name char,word char,mean char,time char);";char *errmsg = NULL;char *name = save_buf;if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK){fprintf(stderr,"sqlite3_exec: %s __%d__\n",errmsg,__LINE__);return -1;}//插入记录sprintf(sql,"insert into history values (\"%s\",\"%s\", \"%s\",\"%s\");",name,words, mean,mytime);if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){printf("sqlite3_exec failed:%s __%d__\n", errmsg, __LINE__);return -1;}printf("Insert success...\n");
}//查询单词
int Search(sqlite3 *db,char *buf,char *save_buf)
{//打开数据库if(sqlite3_open("./dict.db",&db) != SQLITE_OK){fprintf(stderr,"sqlite3_open: %s __%d__\n",sqlite3_errmsg(db),__LINE__);return -1;}char sql[128] = "select * from dict;";char **pres = NULL;int row,column;char *errmsg = NULL;if(sqlite3_get_table(db,sql,&pres,&row,&column,&errmsg) != SQLITE_OK){fprintf(stderr,"sqlite3_get_table: %s __%d__\n",errmsg,__LINE__);return -1;}char *words = buf+2;for(int i=0;i<(row+1)*column;i++){if(strcmp(pres[i],words) == 0){//若查询成功,则将该单词插入记录Insert(db,words,pres[i+1],save_buf);bzero(buf, sizeof(buf));sprintf(buf,"\t%s\t\t%s\t",pres[i],pres[i+1]);if(sqlite3_close(db) != SQLITE_OK){printf("sqlite3_close failed:%s __%d__\n", sqlite3_errmsg(db), __LINE__);return -1;}return 4;}}//关闭数据库,释放对应的内存空间if(sqlite3_close(db) != SQLITE_OK){printf("sqlite3_close failed:%s __%d__\n", sqlite3_errmsg(db), __LINE__);return -1;}return 5;
}
4.1.5 查找历史记录
主要流程:
- 创建并打开数据库
- 创建数据表
- 匹配当前登录的用户名,若存在记录,则返回记录信息,若不存在,则查找失败
- 关闭数据库
//查询记录
int Search_res(sqlite3 *db,char *buf,char *save_buf)
{//打开数据库if(sqlite3_open("./dict.db",&db) != SQLITE_OK){fprintf(stderr,"sqlite3_open: %s __%d__\n",sqlite3_errmsg(db),__LINE__);return -1;}char sql[128] = "create table if not exists history (name char,word char,mean char,time char);";char *errmsg = NULL;if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK){fprintf(stderr,"sqlite3_exec: %s __%d__\n",errmsg,__LINE__);return -1;}char msg[128] = "";strcpy(sql,"select * from history;");char **pres = NULL;int row,column;if(sqlite3_get_table(db,sql,&pres,&row,&column,&errmsg) != SQLITE_OK){fprintf(stderr,"sqlite3_get_table: %s __%d__\n",errmsg,__LINE__);return -1;}bzero(buf,sizeof(buf));for(int i=4;i<(row+1)*column;i++){if(i%4==0 && strcmp(save_buf,pres[i]) == 0){sprintf(msg,"%s\t%s\t%s\t%s\n",pres[i],pres[i+1],pres[i+2],pres[i+3]);strcat(buf,msg);}}if(strlen(buf)!=0)*(buf+strlen(buf)-1) = 0;//关闭数据库,释放对应的内存空间if(sqlite3_close(db) != SQLITE_OK){printf("sqlite3_close failed:%s __%d__\n", sqlite3_errmsg(db), __LINE__);return -1;}if(strlen(buf) == 0)return 7;return 6;
}
4.2 客户端实现功能代码
#include "head.h"
int main(int argc, const char *argv[])
{sqlite3 *db = NULL;//创建流式套接字int cfd = socket(AF_INET,SOCK_STREAM,0);if(cfd < 0){perror("socket");fprintf(stderr,"socket failed __%d__\n",__LINE__);return -1;}printf("socket success...\n");//设置允许端口号复用int reuse = 1;if(setsockopt(cfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) {perror("setsockopt");return -1;}//填充地址信息结构体,真是的地址信息结构体根据地址族制定struct sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port = htons(PORT);sin.sin_addr.s_addr = inet_addr(IP);//连接服务器if(connect(cfd,(struct sockaddr *)&sin,sizeof(sin)) < 0){perror("connetc");return -1;}printf("connect success...\n");ssize_t res = 0;char buf[128] = "";char save_buf[128] = "";while(1){system("clear");printf("--------------------------\n");printf("--------1.REGISTER--------\n");printf("--------2.LOGIN-----------\n");printf("--------3.EXIE------------\n");printf("--------------------------\n");bzero(buf,sizeof(buf));printf("please enter>>>");fgets(buf,sizeof(buf),stdin);buf[strlen(buf)-1] = 0;char name[20] = "";char passwd[20] = "";if(strcmp(buf,"1") == 0){printf("please enter name>>>");scanf("%s",name);getchar();printf("please enter passwd>>>");scanf("%s",passwd);getchar();sprintf(buf,"%s%c%s%c%s","1",0,name,0,passwd);}else if(strcmp(buf,"2") == 0){printf("please enter name>>>");scanf("%s",name);getchar();printf("please enter passwd>>>");scanf("%s",passwd);getchar();sprintf(buf,"%s%c%s%c%s","2",0,name,0,passwd);}else if(strcmp(buf,"3") == 0)break;//发送数据if(send(cfd,buf,sizeof(buf),0) < 0){perror("send");return -1;}//接受数据bzero(buf,sizeof(buf));res = recv(cfd,buf,sizeof(buf),0);if(res < 0){perror("recv");return -1;}else if(0 == res){printf("[%s : %d] server offline\n",IP,PORT);break;}printf("%s\n",buf);//另存bufstrcpy(save_buf,buf);while(strcmp(save_buf,"[login success!]") == 0){system("clear");printf("--------------------------\n");printf("-------1.SEARCH WORDS-----\n");printf("-------2.HISTORICAL ------\n");printf("-------3.EXIE LOGIN-------\n");printf("--------------------------\n");bzero(buf,sizeof(buf));printf("please enter>>>");fgets(buf,sizeof(buf),stdin);buf[strlen(buf)-1] = 0;char words[20] = "";if(strcmp(buf,"1") == 0){while(1){bzero(buf,sizeof(buf));printf("please enter word(enter \"quit\" finished)>>>");scanf("%s",words);getchar();if(strcmp(words,"quit#") == 0)break;sprintf(buf,"%s%c%s%c","3",0,words,0);//发送数据if(send(cfd,buf,sizeof(buf),0) < 0){perror("send");return -1;}//接收查询单词结果bzero(buf,sizeof(buf));res = recv(cfd,buf,sizeof(buf),0);if(res < 0){perror("recv");return -1;}else if(0 == res){printf("[%s : %d] server offline\n",IP,PORT);// break;goto END;}printf("%s\n",buf);}}else if(strcmp(buf,"2") == 0){sprintf(buf,"%s%c","4",0);//发送数据if(send(cfd,buf,sizeof(buf),0) < 0){perror("send");return -1;}//接受查询单词结果bzero(buf,sizeof(buf));res = recv(cfd,buf,sizeof(buf),0);if(res < 0){perror("recv");return -1;}else if(0 == res){printf("[%s : %d] server offline\n",IP,PORT);goto END;// break;}printf("%s\n",buf);}else if(strcmp(buf,"3") == 0)break;printf("enter any character to clear>>>");while(getchar()!=10);}printf("enter any character to clear>>>");while(getchar()!=10);}
END://关闭所有文件描述符close(cfd);return 0;
}
五、完整代码
5.1 头文件
#ifndef __HEAD_H__
#define __HEAD_H__#include <stdio.h>
#include <sqlite3.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <time.h>#define PORT 8808
//#define IP "192.168.122.92"
#define IP "10.102.144.7"
#define ERR_MSG(msg) { fprintf(stderr,"__%d__",__LINE__); perror(msg); }int import_dict(sqlite3 *db);
int Register(sqlite3 *db,char *buf);
int Login(sqlite3 *db,char *buf);
int Search(sqlite3 *db,char *buf,char *save_buf);
int Insert(sqlite3 *db,char *words,char *mean,char *save_buf);
int do_select_user(sqlite3 *db,char *name);
void handler(int sig);
int deal_cli_msg(int newfd,struct sockaddr_in cin,sqlite3 *db);
int Search_res(sqlite3 *db,char *buf,char *save_buf);#endif
5.2 功能函数
#include "head.h"//导入词典
int import_dict(sqlite3 *db)
{if(sqlite3_open("./dict.db",&db) != SQLITE_OK){fprintf(stderr,"sqlite3_open: %s __%d__\n",sqlite3_errmsg(db),__LINE__);return -1;}//创建一个表char sql[128] = "create table if not exists dict (word char,mean char);";char *errmsg = NULL;if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK){fprintf(stderr,"sqlite3_exec: %s __%d__\n",errmsg,__LINE__);return -1;}//打开文件FILE* fp = fopen("./dict.txt", "r");if(NULL == fp){perror("fopen");return -1;}//循环读取文件中的数据,一行一行的读取char buf[256] = "";char word[32] = "";char mean[200] = "";int count = 1;int i = 0;char* ptr = NULL;printf("importing dictionary...\n");while(1){if(fgets(buf, sizeof(buf), fp) == NULL)break;buf[strlen(buf)-1] = 0;//分离单词和意思bzero(word, sizeof(word));bzero(mean, sizeof(mean));//获取" "子串在buf中的地址ptr = strstr(buf, " ");if(NULL == ptr){printf("没有找到对应子串\n");break;}strncpy(word, buf, ptr-buf); //" "子串前面是单词strcpy(mean, ptr+3); //" "子串后面是意思 //插入到数据库中sprintf(sql,"insert into dict values (\"%s\", \"%s\");", word, mean);if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){printf("sqlite3_exec failed:%s __%d__\n", errmsg, __LINE__);return -1;}}//关闭文件fclose(fp);//关闭数据库,释放对应的内存空间if(sqlite3_close(db) != SQLITE_OK){printf("sqlite3_close failed:%s __%d__\n", sqlite3_errmsg(db), __LINE__);return -1;}printf("dictionary import completed...\n");return 0;
}//匹配用户名是否存在
int do_select_user(sqlite3 *db,char *name)
{char sql[128] = "select name from user;";char **pres = NULL;int row,column;char *errmsg = NULL;if(sqlite3_get_table(db,sql,&pres,&row,&column,&errmsg) != SQLITE_OK){fprintf(stderr,"sqlite3_exec: %s __%d__\n",errmsg,__LINE__);return -1;}for(int i=1;i<(row+1)*column;i++){if(strcmp(pres[i],name) == 0){fprintf(stderr,"sqlite3_exec: name already existss\n");return 1;}}return 0;
}
//实现注册功能
int Register(sqlite3 *db,char *buf)
{//打开数据库if(sqlite3_open("./dict.db",&db) != SQLITE_OK){fprintf(stderr,"sqlite3_open: %s __%d__\n",sqlite3_errmsg(db),__LINE__);return -1;}//创建一个表char sql[128] = "create table if not exists user (name char,passwd char);";char *errmsg = NULL;if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK){fprintf(stderr,"sqlite3_exec: %s __%d__\n",errmsg,__LINE__);return -1;}char *name = buf+2;char *passwd = buf+2+strlen(buf+2)+1;if(do_select_user(db,name) == 1){if(sqlite3_close(db) != SQLITE_OK){printf("sqlite3_close failed:%s __%d__\n", sqlite3_errmsg(db), __LINE__);return -1;}return 1;}sprintf(sql,"insert into user values ('%s','%s');",name,passwd);if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK){fprintf(stderr,"sqlite3_exec: %s __%d__\n",errmsg,__LINE__);return -1;}printf("register success...\n");//关闭数据库,释放对应的内存空间if(sqlite3_close(db) != SQLITE_OK){printf("sqlite3_close failed:%s __%d__\n", sqlite3_errmsg(db), __LINE__);return -1;}return 0;
}
//实现登录功能
int Login(sqlite3 *db,char *buf)
{//打开数据库if(sqlite3_open("./dict.db",&db) != SQLITE_OK){fprintf(stderr,"sqlite3_open: %s __%d__\n",sqlite3_errmsg(db),__LINE__);return -1;}char sql[128] = "create table if not exists user (name char,passwd char);";char *errmsg = NULL;if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK){fprintf(stderr,"sqlite3_exec: %s __%d__\n",errmsg,__LINE__);return -1;}strcpy(sql,"select * from user;");char **pres = NULL;int row,column;if(sqlite3_get_table(db,sql,&pres,&row,&column,&errmsg) != SQLITE_OK){fprintf(stderr,"sqlite3_exec: %s __%d__\n",errmsg,__LINE__);return -1;}char *name = buf+2;char *passwd = buf+2+strlen(buf+2)+1;for(int i=2;i<(row+1)*column;i++){if(strcmp(pres[i],name) == 0 && strcmp(pres[i+1],passwd) == 0){printf("login success...\n");if(sqlite3_close(db) != SQLITE_OK){printf("sqlite3_close failed:%s __%d__\n", sqlite3_errmsg(db), __LINE__);return -1;}return 2;}}//关闭数据库,释放对应的内存空间if(sqlite3_close(db) != SQLITE_OK){printf("sqlite3_close failed:%s __%d__\n", sqlite3_errmsg(db), __LINE__);return -1;}return 3;
}
//插入记录
int Insert(sqlite3 *db,char *words,char *mean,char *save_buf)
{//获取当前时间time_t t;struct tm *info=NULL;char mytime[128] = "";t = time(NULL);info = localtime(&t);sprintf(mytime,"%d-%02d-%02d %02d:%02d:%02d",info->tm_year+1900,info->tm_mon+1,info->tm_mday,info->tm_hour,info->tm_min,info->tm_sec);//打开数据库if(sqlite3_open("./dict.db",&db) != SQLITE_OK){fprintf(stderr,"sqlite3_open: %s __%d__\n",sqlite3_errmsg(db),__LINE__);return -1;}//创建一个表char sql[128] = "create table if not exists history (name char,word char,mean char,time char);";char *errmsg = NULL;char *name = save_buf;if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK){fprintf(stderr,"sqlite3_exec: %s __%d__\n",errmsg,__LINE__);return -1;}//插入记录sprintf(sql,"insert into history values (\"%s\",\"%s\", \"%s\",\"%s\");",name,words, mean,mytime);if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){printf("sqlite3_exec failed:%s __%d__\n", errmsg, __LINE__);return -1;}printf("Insert success...\n");
}//查询单词
int Search(sqlite3 *db,char *buf,char *save_buf)
{//打开数据库if(sqlite3_open("./dict.db",&db) != SQLITE_OK){fprintf(stderr,"sqlite3_open: %s __%d__\n",sqlite3_errmsg(db),__LINE__);return -1;}char sql[128] = "select * from dict;";char **pres = NULL;int row,column;char *errmsg = NULL;if(sqlite3_get_table(db,sql,&pres,&row,&column,&errmsg) != SQLITE_OK){fprintf(stderr,"sqlite3_get_table: %s __%d__\n",errmsg,__LINE__);return -1;}char *words = buf+2;for(int i=0;i<(row+1)*column;i++){if(strcmp(pres[i],words) == 0){//若查询成功,则将该单词插入记录Insert(db,words,pres[i+1],save_buf);bzero(buf, sizeof(buf));sprintf(buf,"\t%s\t\t%s\t",pres[i],pres[i+1]);if(sqlite3_close(db) != SQLITE_OK){printf("sqlite3_close failed:%s __%d__\n", sqlite3_errmsg(db), __LINE__);return -1;}return 4;}}//关闭数据库,释放对应的内存空间if(sqlite3_close(db) != SQLITE_OK){printf("sqlite3_close failed:%s __%d__\n", sqlite3_errmsg(db), __LINE__);return -1;}return 5;
}//查询记录
int Search_res(sqlite3 *db,char *buf,char *save_buf)
{//打开数据库if(sqlite3_open("./dict.db",&db) != SQLITE_OK){fprintf(stderr,"sqlite3_open: %s __%d__\n",sqlite3_errmsg(db),__LINE__);return -1;}char sql[128] = "create table if not exists history (name char,word char,mean char,time char);";char *errmsg = NULL;if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK){fprintf(stderr,"sqlite3_exec: %s __%d__\n",errmsg,__LINE__);return -1;}char msg[128] = "";strcpy(sql,"select * from history;");char **pres = NULL;int row,column;if(sqlite3_get_table(db,sql,&pres,&row,&column,&errmsg) != SQLITE_OK){fprintf(stderr,"sqlite3_get_table: %s __%d__\n",errmsg,__LINE__);return -1;}bzero(buf,sizeof(buf));for(int i=4;i<(row+1)*column;i++){if(i%4==0 && strcmp(save_buf,pres[i]) == 0){sprintf(msg,"%s\t%s\t%s\t%s\n",pres[i],pres[i+1],pres[i+2],pres[i+3]);strcat(buf,msg);}}if(strlen(buf)!=0)*(buf+strlen(buf)-1) = 0;//关闭数据库,释放对应的内存空间if(sqlite3_close(db) != SQLITE_OK){printf("sqlite3_close failed:%s __%d__\n", sqlite3_errmsg(db), __LINE__);return -1;}if(strlen(buf) == 0)return 7;return 6;
}
//服务器子进程处理客户端信息
int deal_cli_msg(int newfd,struct sockaddr_in cin,sqlite3 *db)
{int flag = 0; char buf[128] = "";char save_buf[128] = "";ssize_t res = 0;int f_res = -1;while(1){bzero(buf, sizeof(buf));//接收数据res = recv(newfd, buf, sizeof(buf), 0);if(res < 0){ERR_MSG("recv");return -1;}else if(0 == res){printf("[%s : %d] client offline\n",inet_ntoa(cin.sin_addr), ntohs(cin.sin_port)); break;}//调用功能函数if(strcmp(buf,"1") == 0)f_res = Register(db,buf); //注册else if(strcmp(buf,"2") == 0){f_res = Login(db,buf); //登录strcpy(save_buf,buf+2); //将用户名另存}else if(strcmp(buf,"3") == 0){f_res = Search(db,buf,save_buf); //查询单词}else if(strcmp(buf,"4") == 0)f_res = Search_res(db,buf,save_buf); //查询记录//发送数据if(0 == f_res){bzero(buf, sizeof(buf));strcpy(buf,"[register success!]");}else if(1 == f_res){ bzero(buf, sizeof(buf));strcpy(buf,"[register failed,name already exists!]");}else if(2 == f_res){bzero(buf, sizeof(buf));strcpy(buf,"[login success!]");}else if(3 == f_res){bzero(buf, sizeof(buf));strcpy(buf,"[login failed,name/passwd does not exists!]");}else if(4 == f_res){}else if(5 == f_res){bzero(buf, sizeof(buf));strcpy(buf,"[words not find!]");}else if(6 == f_res){}else if(7 == f_res){bzero(buf, sizeof(buf));strcpy(buf,"[not find history!]");}if(send(newfd, buf, sizeof(buf), 0) < 0){ERR_MSG("send");return -1;}}close(newfd);return 0;
}
//捕获信号
void handler(int sig)
{while(waitpid(-1, NULL, WNOHANG) > 0);
}
5.3 服务器
#include "head.h"
int main(int argc, const char *argv[])
{sqlite3 *db = NULL;if(signal(17, handler) == SIG_ERR){ERR_MSG("signal");return -1;}//导入词典import_dict(db);//创建流式套接字int sfd = socket(AF_INET,SOCK_STREAM,0);if(sfd < 0){ERR_MSG("socket");return -1;}//设置允许端口号复用int reuse = 1;if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) { perror("setsockopt");return -1;}//绑定服务器IP和端口号struct sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port = htons(PORT);sin.sin_addr.s_addr = inet_addr(IP);if(bind(sfd,(struct sockaddr *)&sin,sizeof(sin)) < 0){ERR_MSG("bind");return -1;}//将套接字设置为被动监听状态if(listen(sfd,10) < 0){ERR_MSG("listen");return -1;}int newfd = -1;struct sockaddr_in cin;socklen_t addrlen = sizeof(cin);//从已完成连接的队列中获取一个客户端信息,生成一个新的文件描述符while(1){newfd = accept(sfd,(struct sockaddr *)&cin,&addrlen);if(newfd < 0){ERR_MSG("accept");return -1;}printf("[%s : %d] connect success...\n",inet_ntoa(cin.sin_addr), ntohs(cin.sin_port));if(0 == fork()){close(sfd);deal_cli_msg(newfd,cin,db);exit(0);}close(newfd);}close(sfd);return 0;
}
5.4 客户端
#include "head.h"
int main(int argc, const char *argv[])
{sqlite3 *db = NULL;//创建流式套接字int cfd = socket(AF_INET,SOCK_STREAM,0);if(cfd < 0){perror("socket");fprintf(stderr,"socket failed __%d__\n",__LINE__);return -1;}printf("socket success...\n");//设置允许端口号复用int reuse = 1;if(setsockopt(cfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) {perror("setsockopt");return -1;}//填充地址信息结构体,真是的地址信息结构体根据地址族制定struct sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port = htons(PORT);sin.sin_addr.s_addr = inet_addr(IP);//连接服务器if(connect(cfd,(struct sockaddr *)&sin,sizeof(sin)) < 0){perror("connetc");return -1;}printf("connect success...\n");ssize_t res = 0;char buf[128] = "";char save_buf[128] = "";while(1){system("clear");printf("--------------------------\n");printf("--------1.REGISTER--------\n");printf("--------2.LOGIN-----------\n");printf("--------3.EXIE------------\n");printf("--------------------------\n");bzero(buf,sizeof(buf));printf("please enter>>>");fgets(buf,sizeof(buf),stdin);buf[strlen(buf)-1] = 0;char name[20] = "";char passwd[20] = "";if(strcmp(buf,"1") == 0){printf("please enter name>>>");scanf("%s",name);getchar();printf("please enter passwd>>>");scanf("%s",passwd);getchar();sprintf(buf,"%s%c%s%c%s","1",0,name,0,passwd);}else if(strcmp(buf,"2") == 0){printf("please enter name>>>");scanf("%s",name);getchar();printf("please enter passwd>>>");scanf("%s",passwd);getchar();sprintf(buf,"%s%c%s%c%s","2",0,name,0,passwd);}else if(strcmp(buf,"3") == 0)break;//发送数据if(send(cfd,buf,sizeof(buf),0) < 0){perror("send");return -1;}//接受数据bzero(buf,sizeof(buf));res = recv(cfd,buf,sizeof(buf),0);if(res < 0){perror("recv");return -1;}else if(0 == res){printf("[%s : %d] server offline\n",IP,PORT);break;}printf("%s\n",buf);//另存bufstrcpy(save_buf,buf);while(strcmp(save_buf,"[login success!]") == 0){system("clear");printf("--------------------------\n");printf("-------1.SEARCH WORDS-----\n");printf("-------2.HISTORICAL ------\n");printf("-------3.EXIE LOGIN-------\n");printf("--------------------------\n");bzero(buf,sizeof(buf));printf("please enter>>>");fgets(buf,sizeof(buf),stdin);buf[strlen(buf)-1] = 0;char words[20] = "";if(strcmp(buf,"1") == 0){while(1){bzero(buf,sizeof(buf));printf("please enter word(enter \"quit\" finished)>>>");scanf("%s",words);getchar();if(strcmp(words,"quit") == 0)break;sprintf(buf,"%s%c%s%c","3",0,words,0);//发送数据if(send(cfd,buf,sizeof(buf),0) < 0){perror("send");return -1;}//接收查询单词结果bzero(buf,sizeof(buf));res = recv(cfd,buf,sizeof(buf),0);if(res < 0){perror("recv");return -1;}else if(0 == res){printf("[%s : %d] server offline\n",IP,PORT);// break;goto END;}printf("%s\n",buf);}}else if(strcmp(buf,"2") == 0){sprintf(buf,"%s%c","4",0);//发送数据if(send(cfd,buf,sizeof(buf),0) < 0){perror("send");return -1;}//接受查询单词结果bzero(buf,sizeof(buf));res = recv(cfd,buf,sizeof(buf),0);if(res < 0){perror("recv");return -1;}else if(0 == res){printf("[%s : %d] server offline\n",IP,PORT);goto END;// break;}printf("%s\n",buf);}else if(strcmp(buf,"3") == 0)break;printf("enter any character to clear>>>");while(getchar()!=10);}printf("enter any character to clear>>>");while(getchar()!=10);}
END://关闭所有文件描述符close(cfd);return 0;
}
相关文章:

项目——电子词典(客户端、服务器交互,字典导入,单词查询)
一、项目要求 登录注册功能,不能重复登录,重复注册单词查询功能历史记录功能,存储单词,意思,以及查询时间基于TCP,支持多客户端连接采用数据库保存用户信息与历史记录将dict.txt的数据导入到数据库中保存。…...

jenkins 是什么?
一、jenkins 是什么? Jenkins是一个开源的、提供友好操作界面的持续集成(CI)工具,起源于Hudson,主要用于持续、自动的构建/测试软件项目、监控外部任务的运行。Jenkins用Java语言编写,可在Tomcat等流行的servlet容器中运行&#…...

无涯教程-PHP - sql_regcase()函数
sql_regcase() - 语法 string sql_regcase (string string) 可以将sql_regcase()函数视为实用程序函数,它将输入参数字符串中的每个字符转换为包含两个字符的带括号的表达式。 sql_regcase() - 返回值 返回带括号的表达式字符串以及转换后的字符。 sql_regcase…...
cesium 实现鼠标中键拖动地图
cesium默认左键拖动地图,中键旋转,再绘图时带来诸多不便。所以改成鼠标中键按下拖动地图,鼠标左键选点。代码如下:【感谢chatGPT】 //改为中建拖动// 假设 viewer 是你的 Cesium Viewer 实例const cameraController viewer.scene…...

低压风机单片机方案
低压风机通常由电机、转子、机壳、进气管、出气管、齿轮和减速机等组成。电机带动转子旋转,旋转的转子带动齿轮和减速机转动,进而形成空气被吸入转子内部,通过旋转而产生的离心力把气体压缩,并将气体排出。 低压风机方案的主控型…...
R语言06-R语言的基本运算
概念 R语言支持多种基本运算,包括算术运算、逻辑运算、比较运算和向量化运算等。 代码示意 逻辑运算 a <- TRUE b <- FALSElogical_and <- a & b # 逻辑与 logical_or <- a | b # 逻辑或 logical_not <- !a # 逻辑非比较运算 x <…...

Docker容器:docker-compose管理创建LNMP服务并运行Wordpress网站平台
文章目录 一.项目环境1. 环境描述2.项目需求 二.部署过程1.安装Docker2.安装Docker加速器3.Docker-Compose安装部署4.准备依赖文件、配置nginx5.配置mysql6.配置php7.编写docker-compose.yml8.验证 三.容器快照,然后将Docker镜像打包成tar包备…...

实业兴国 守护种源 —— 白露木實®农业的活力之风
高科技领域,芯片是生命线;而在农业领域,种源与芯片在高科技领域的重要性是相同的。保护、发展、培育我国的种质资源,是中国农业发展至为关键的一环。但是,因为思想、观念、认识、技术等方面的原因,让我们错…...
Web3.0
一、Web3.0是什么 Web3.0(有时称为“分布式Web”或“去中心化Web”)是对互联网的下一代演进的概念。它代表了一种更加分散、去中心化和用户掌控的互联网模式,与传统的Web2.0模型有很大不同。 以下是Web3.0的一些关键特征和概念:…...

精密图纸被窃,知名手表品牌Seiko遭BlackCat勒索软件攻击
据BleepingComputer消息,日本著名手表制造商Seiko在7月末遭到了网络攻击,8月21日,BlackCat(又名ALPHV)勒索软件组织在其网站上宣布对这起攻击事件负责。 8 月 10 日,Seiko发布了一份数据泄露通知࿰…...

K8S如何部署Redis(单机、集群)
在今天的讨论中,我们将深入研究如何将Redis数据库迁移到云端,以便更好地利用云计算的优势提高数据管理的灵活性。 Redis(Remote Dictionary Server)是一个开源的、基于内存的数据结构存储系统,它可以用作数据库、缓存和消息代理。Redis支持多…...

Flask狼书笔记 | 03_模板
文章目录 3 模板3.1 模板基本使用3.2 模板结构组织3.3 模板进阶 3 模板 模板(template):包含固定内容和动态部分的可重用文件。Jinja2模板引擎可用于任何纯文本文件。 3.1 模板基本使用 HTML实体:https://dev.w3.org/html5/htm…...

MySQL 数据备份和数据恢复
目录 一、数据备份 1、概述 2、MySQLdump命令备份 1)备份单个数据库中的所有表 2) 备份数据中某个或多个表 3) 备份所有数据库 4)备份多个库 5) 只备份一个表或多个表结构 二、数据恢复 三、数据备份与恢复应用 一、数据备份 1、概述 数据备…...
软考高级系统架构设计师系列论文八十二:论软件的可维护性设计
软考高级系统架构设计师系列论文八十二:论软件的可维护性设计 一、摘要二、正文三、总结一、摘要 随着软件大型化,复杂化的发展,软件维护所耗费的资源越来越多,软件可维护性设计日益得到重视。我单位近几年开发综合业务 ATM交换机,用户对交换机的可维护性要求很高。我参加…...

Ompl初探
在/ompl-1.x.0/build/Release/bin下有很多生成的demo可执行文件 在终端执行 ./demo_Point2DPlanning 测试程序 #include <ompl/base/SpaceInformation.h> #include <ompl/base/spaces/SE3StateSpace.h> #include <ompl/base/StateSpace.h> #include <o…...
android sdk打包aar方案步骤
1.使用fat-aar库https://github.com/kezong/fat-aar-android/blob/master/README_CN.md 第一步:添加以下代码到你工程根目录下的build.gradle文件中: For Maven Central (The lastest release is available on Maven Central): buildscript {repositories {maven…...
Redis之bitmap类型解读
目录 基本介绍 基本命令 Setbit Getbit BITCOUNT 应用场景 统计当日活跃用户 用户签到 bitmap - Redis布隆过滤器 (应对缓存穿透问题) 基本介绍 Redis 的位图(bitmap)是由多个二进制位组成的数组,只有两…...

stm32之10.系统定时器
delay_s()延时秒 delay_ms()毫秒*1000 delay_us()微秒*1000000 微秒定时器代码 void delay_us(uint32_t n) { SysTick->CTRL 0; // Disable SysTick,关闭系统定时器 SysTick->LOAD SystemCoreClock/1000000*n-1; // 就是nus SysTick->LOAD Sys…...
PyTorch安装教程:从头开始配置PyTorch环境
PyTorch是一个开源的机器学习框架,广泛用于深度学习任务。要开始使用PyTorch,您需要在计算机上正确配置PyTorch环境。本文将为您提供一步步的指南,帮助您成功安装和配置PyTorch。 第一部分:安装Python和相关工具 第一步…...

Docker拉取并配置Grafana
Linux下安装Docker请参考:Linux安装Docker 安装准备 新建挂载目录 /opt/grafana/data目录,准备用来挂载放置grafana的数据 /opt/grafana/plugins目录,准备用来放置grafana的插件 /opt/grafana/config目录,准备用来挂载放置graf…...

【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...

python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...

视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...

算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...