一、思维导图

二、词典
1、服务器
#include <myhead.h>#define SER_PORT 8888
#define SER_IP "192.168.116.128"
typedef struct acc_pass
{int num;char account[20];int password;
} acc_pass_t;
typedef struct search_query
{int num;char word[50];char account[20];
} search_query_t;
typedef struct search_history
{char client_ip[16];int client_port;char account[20];char search_word[50];char search_result[256];char search_time[20];
} search_history_t;
int insert_word(sqlite3 *ppDb,char *buf1,char *buf2)
{char sql[256]="";snprintf(sql,sizeof(sql),"insert into WORD_TRANSLATE values(\"%s\",\"%s\");",buf1,buf2);char *errmsg=NULL;if (sqlite3_exec(ppDb,sql,NULL,NULL,&errmsg)!=SQLITE_OK){printf("%d插入失败:%s\n",__LINE__,errmsg);sqlite3_free(errmsg);return -1;}return 0;
}
int empty_word(sqlite3 *ppDb)
{char sql[128]="delete from WORD_TRANSLATE;";char *errmsg=NULL;if(sqlite3_exec(ppDb,sql,NULL,NULL,&errmsg)!=SQLITE_OK){printf("%d清空失败:%s\n",__LINE__,errmsg);sqlite3_free(errmsg);return -1;}return 0;
}
int record_search_history(sqlite3 *ppDb,const char *client_ip,int client_port,const char *account,const char *word,const char *result)
{time_t now =time(NULL);struct tm *t =localtime(&now);char timestamp[20];snprintf(timestamp,sizeof(timestamp),"%04d-%02d-%02d %02d:%02d:%02d",t->tm_year + 1900,t->tm_mon + 1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);char sql[512]="";snprintf(sql,sizeof(sql), "insert into SEARCH_HISTORY values(\"%s\",%d,\"%s\",\"%s\",\"%s\",\"%s\");",client_ip,client_port,account,word,result,timestamp);char *errmsg=NULL;if (sqlite3_exec(ppDb,sql,NULL,NULL,&errmsg)!=SQLITE_OK){printf("%d插入搜索历史失败:%s\n",__LINE__,errmsg);sqlite3_free(errmsg);return -1;}return 0;
}
int query_word(sqlite3 *ppDb,const char *word,char *result,int result_size)
{char sql[256]="";snprintf(sql,sizeof(sql),"select translate from WORD_TRANSLATE where word=\"%s\";",word);char *errmsg=NULL;int found=0;int callback(void *data,int argc,char **argv,char **azColName) {if(argc>0&&argv[0]) {strncpy((char*)data,argv[0],result_size-1);found=1;}return 0;}if(sqlite3_exec(ppDb,sql,callback,result,&errmsg)!=SQLITE_OK){printf("%d查询失败%s\n",__LINE__,errmsg);sqlite3_free(errmsg);return -1;}if(!found) {strncpy(result,"未找到该单词",result_size-1);}result[result_size-1]='\0';return 0;
}
int query_search_history(sqlite3 *ppDb,const char *account,char *result,int result_size)
{char sql[256]="";snprintf(sql,sizeof(sql),"select search_time,search_word,search_result from SEARCH_HISTORY where account=\"%s\" order by search_time desc;", account);char *errmsg=NULL;result[0]='\0';int count=0;int callback(void *data,int argc,char **argv,char **azColName) {char *res=(char *)data;char line[512];snprintf(line,sizeof(line),"时间: %s\n单词: %s\n结果: %s\n\n",argv[0],argv[1],argv[2]);if(strlen(res)+strlen(line)<(size_t)(result_size-1)) {strcat(res,line);count++;}return 0;}if(sqlite3_exec(ppDb,sql,callback,result,&errmsg)!=SQLITE_OK){printf("%d查询历史记录失败:%s\n",__LINE__,errmsg);sqlite3_free(errmsg);return -1;}if(count==0) {strncpy(result,"无搜索历史记录",result_size-1);result[result_size-1]='\0';}return 0;
}
int insert_account(sqlite3 *ppDb,const char *account,int password)
{char check_sql[256]="";snprintf(check_sql,sizeof(check_sql),"select * from ACCOUNT_PASSWORD where account=\"%s\";",account);char *errmsg=NULL;int exists=0;int check_callback(void *data,int argc,char **argv,char **azColName) {*(int*)data=1;return 0;}if(sqlite3_exec(ppDb,check_sql,check_callback,&exists,&errmsg)!=SQLITE_OK){printf("%d查询账号失败:%s\n",__LINE__,errmsg);sqlite3_free(errmsg);return -1;}if(exists) {printf("账号已存在\n");return -1;}char sql[256] = "";snprintf(sql, sizeof(sql), "insert into ACCOUNT_PASSWORD values(\"%s\",%d,0);", account, password);if (sqlite3_exec(ppDb, sql, NULL, NULL, &errmsg) != SQLITE_OK){printf("%d插入账号失败:%s\n",__LINE__,errmsg);sqlite3_free(errmsg);return -1;}return 0;
}
int empty_account(sqlite3 *ppDb)
{char sql[128]="delete from ACCOUNT_PASSWORD;";char *errmsg=NULL;if (sqlite3_exec(ppDb,sql,NULL,NULL,&errmsg)!=SQLITE_OK){printf("%d清空账号表失败:%s\n",__LINE__,errmsg);sqlite3_free(errmsg);return -1;}return 0;
}
int enter_account(sqlite3 *ppDb,const char *account,int password)
{char sql[256]="";snprintf(sql, sizeof(sql), "select * from ACCOUNT_PASSWORD where account=\"%s\" and password=%d and flag=0;",account, password);char *errmsg=NULL;int exists=0;int callback(void *data,int argc,char **argv,char **azColName) {*(int*)data=1;return 0;}if (sqlite3_exec(ppDb,sql,callback,&exists,&errmsg)!=SQLITE_OK){printf("%d查询账号失败:%s\n",__LINE__,errmsg);sqlite3_free(errmsg);return -1;}if (!exists) {return -1; }snprintf(sql,sizeof(sql),"update ACCOUNT_PASSWORD set flag=1 where account=\"%s\" and password=%d;",account,password);if (sqlite3_exec(ppDb,sql,NULL,NULL,&errmsg)!=SQLITE_OK){printf("%d更新登录状态失败:%s\n",__LINE__,errmsg);sqlite3_free(errmsg);return -1;}return 0;
}
int break_account(sqlite3 *ppDb,const char *account,int password)
{char sql[256]="";snprintf(sql,sizeof(sql),"update ACCOUNT_PASSWORD set flag=0 where account=\"%s\" and password=%d;",account, password);char *errmsg=NULL;if(sqlite3_exec(ppDb,sql,NULL,NULL,&errmsg)!=SQLITE_OK){printf("%d更新退出状态失败:%s\n",__LINE__,errmsg);sqlite3_free(errmsg);return -1;}return 0;
}
void handle_client(int new_fd,struct sockaddr_in cin,sqlite3 *ppDb)
{char client_ip[16] = {0};inet_ntop(AF_INET,&cin.sin_addr.s_addr,client_ip,sizeof(client_ip));int client_port=ntohs(cin.sin_port);printf("[%s:%d]连接成功,new_fd=%d\n",client_ip,client_port,new_fd);acc_pass_t p;search_query_t query;int flag;char result[4096]={0};char current_account[20]={0}; while(1){memset(&p,0,sizeof(acc_pass_t));int res=recv(new_fd,&p,sizeof(acc_pass_t),0);if(res<=0){if(res==0){printf("客户端[%s:%d]已下线\n",client_ip,client_port);if(strlen(current_account)>0){break_account(ppDb,current_account,p.password);}}else{perror("recv error");}break;}printf("收到客户端[%s:%d]请求: num=%d\n",client_ip,client_port,p.num);switch(p.num){case 1: printf("注册账号: %s, %d\n",p.account,p.password);flag=insert_account(ppDb,p.account,p.password);break;case 2: printf("登录账户:%s,%d\n",p.account,p.password);flag=enter_account(ppDb,p.account,p.password);if(flag==0){strcpy(current_account,p.account);}send(new_fd,&flag,sizeof(flag),0);break;case 3: printf("退出账户:%s,%d\n",p.account,p.password);flag=break_account(ppDb,p.account,p.password);if(flag==0){memset(current_account,0,sizeof(current_account));}send(new_fd,&flag,sizeof(flag),0);break;case 4: printf("查询单词请求\n");memset(&query,0,sizeof(query));if(recv(new_fd,&query,sizeof(query),0)<=0){perror("recv query error");flag=-1;break;}printf("用户[%s]查询单词:%s\n",query.account,query.word);memset(result,0,sizeof(result));if (query_word(ppDb,query.word,result,sizeof(result))==0){send(new_fd,result,strlen(result)+1,0);record_search_history(ppDb,client_ip,client_port, query.account, query.word, result);}else{send(new_fd,"查询失败",strlen("查询失败")+1,0);}break;case 5: printf("查询历史记录请求,用户:%s\n",p.account);memset(result,0,sizeof(result));if(query_search_history(ppDb,p.account,result,sizeof(result))==0){send(new_fd,result,strlen(result)+1,0);}else{send(new_fd,"查询历史记录失败",strlen("查询历史记录失败")+1,0);}break;default:printf("未知请求:%d\n",p.num);break;}}close(new_fd);printf("[%s:%d]连接关闭,new_fd=%d\n",client_ip,client_port,new_fd);
}
void handle_sigchild(int sig)
{while (waitpid(-1,NULL,WNOHANG)>0);
}
int main(int argc, const char *argv[])
{signal(SIGCHLD,handle_sigchild);int fd = open("./dict.txt",O_RDONLY);if(fd==-1){ERR_MSG("open dict.txt error");}sqlite3 *ppDb=NULL;if (sqlite3_open("./dict.db",&ppDb)!=SQLITE_OK){printf("sqlite3_open error: %s\n",sqlite3_errmsg(ppDb));close(fd);return -1;}char *sql="create table if not exists WORD_TRANSLATE(word char primary key, translate char);";char *errmsg=NULL;if (sqlite3_exec(ppDb,sql,NULL,NULL,&errmsg)!=SQLITE_OK){printf("创建单词表失败:%s\n",errmsg);sqlite3_free(errmsg);sqlite3_close(ppDb);close(fd);return -1;}empty_word(ppDb); sql = "create table if not exists ACCOUNT_PASSWORD(account char primary key,password int,flag int);"; if (sqlite3_exec(ppDb,sql,NULL,NULL,&errmsg)!=SQLITE_OK){printf("创建账户表失败:%s\n",errmsg);sqlite3_free(errmsg);sqlite3_close(ppDb);close(fd);return -1;}empty_account(ppDb); sql = "create table if not exists SEARCH_HISTORY(client_ip char,client_port int,account char,search_word char,search_result char,search_time char);";if(sqlite3_exec(ppDb,sql,NULL,NULL,&errmsg)!=SQLITE_OK){printf("创建历史表失败:%s\n",errmsg);sqlite3_free(errmsg);}printf("初始化词典中\n");char buf1[128]={0}; char buf2[512]={0}; char buf[1]={0};ssize_t nread;off_t file_size=lseek(fd,0,SEEK_END);lseek(fd,0,SEEK_SET);while (lseek(fd,0,SEEK_CUR)<file_size){memset(buf1,0,sizeof(buf1));memset(buf2,0,sizeof(buf2));int i=0;while (i<sizeof(buf1)-1){nread=read(fd,buf,1);if(nread<=0)break;if(buf[0]==' '||buf[0]=='\t'||buf[0]=='\n'){break;}buf1[i++]=buf[0];}while(1){nread=read(fd,buf,1);if(nread<=0)break;if(buf[0]!=' '&&buf[0]!= '\t'){lseek(fd,-1,SEEK_CUR); break;}}i=0;while(i<sizeof(buf2)-1){nread=read(fd,buf,1);if(nread<=0)break;if(buf[0]=='\n')break;buf2[i++]=buf[0];}if(strlen(buf1)>0){insert_word(ppDb,buf1,buf2);}}close(fd);printf("词典加载完成\n");int sfd=socket(AF_INET,SOCK_STREAM,0);if(-1==sfd){ERR_MSG("socket error");}printf("socket创建成功,sfd = %d\n",sfd);int reuse=1;if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))==-1){ERR_MSG("setsockopt error");}struct sockaddr_in sin;sin.sin_family=AF_INET;sin.sin_port=htons(SER_PORT);sin.sin_addr.s_addr=inet_addr(SER_IP);if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))==-1){ERR_MSG("bind error");}printf("bind成功\n");if(listen(sfd, 128)==-1){ERR_MSG("listen error");}printf("listen成功,等待客户端连接...\n");struct sockaddr_in cin;socklen_t addrlen=sizeof(cin);while(1){int new_fd = accept(sfd,(struct sockaddr*)&cin,&addrlen);if(-1==new_fd){perror("accept error");continue;}pid_t pid=fork();if(pid==0){close(sfd); handle_client(new_fd,cin,ppDb);sqlite3_close(ppDb); exit(EXIT_SUCCESS);}else if(pid>0){close(new_fd); }else{close(new_fd);perror("fork error");}}sqlite3_close(ppDb);close(sfd);return 0;
}
2、客户端
#include <myhead.h>
#define SER_PORT 8888
#define SER_IP "192.168.116.128"
typedef struct acc_pass
{int num;char account[20];int password;
} acc_pass_t;
typedef struct search_query
{int num;char word[50];char account[20];
} search_query_t;
int do_register(int num,acc_pass_t *p,int cfd)
{printf("请输入账号:");scanf("%s",p->account);printf("请输入密码:");scanf("%d",&p->password);p->num=num;if(send(cfd,p,sizeof(acc_pass_t),0)==-1){perror("send register error");return -1;}printf("注册信息发送成功\n");return 0;
}
int do_login(int num,acc_pass_t *p,int cfd)
{printf("请输入账号:");scanf("%s",p->account);printf("请输入密码:");scanf("%d",&p->password);p->num=num;if(send(cfd,p,sizeof(acc_pass_t),0)==-1){perror("send login error");return -1;}int response;if(recv(cfd,&response,sizeof(response),0)==-1){perror("recv response error");return -1;}if (response==0){printf("登录成功\n");return 0;}else{printf("登录失败\n");return -1;}
}
int do_logout(int num,acc_pass_t *p,int cfd)
{p->num=num;if(send(cfd,p,sizeof(acc_pass_t), 0)==-1){perror("send logout error");return -1;}int response;if (recv(cfd,&response,sizeof(response),0)==-1){perror("recv logout response error");return -1;}return response;
}
int do_search_history(int cfd,const char *account)
{acc_pass_t p;memset(&p,0,sizeof(acc_pass_t));p.num=5;strcpy(p.account,account); if(send(cfd,&p,sizeof(acc_pass_t),0)==-1){perror("send history request error");return -1;}char history[4096]={0};int recv_len=recv(cfd,history,sizeof(history)-1,0);if(recv_len==-1){perror("recv history error");return -1;}printf("搜索历史记录:\n%s\n",history);return 0;
}
int do_search_word(int cfd,const char *account)
{acc_pass_t p;memset(&p,0,sizeof(acc_pass_t));p.num=4;strcpy(p.account,account);if (send(cfd,&p,sizeof(acc_pass_t),0)==-1){perror("send search type error");return -1;}search_query_t query;memset(&query,0,sizeof(search_query_t));query.num=4;strcpy(query.account, account);printf("请输入要查询的单词:");scanf("%s",query.word);query.word[strcspn(query.word,"\n")]='\0';if (send(cfd,&query,sizeof(query),0)==-1){perror("send word query error");return -1;}char result[256]={0};int recv_len=recv(cfd,result,sizeof(result)-1,0);if(recv_len==-1){perror("recv word result error");return -1;}printf("查询结果: %s\n",result);return 0;
}int main(int argc, const char *argv[])
{int cfd=socket(AF_INET, SOCK_STREAM, 0);if(-1==cfd){perror("socket error");return -1;}printf("socket创建成功,cfd = %d\n",cfd);struct sockaddr_in sin;sin.sin_family=AF_INET;sin.sin_port=htons(SER_PORT);sin.sin_addr.s_addr=inet_addr(SER_IP);if (connect(cfd,(struct sockaddr*)&sin,sizeof(sin))==-1){perror("connect error");close(cfd);return -1;}printf("连接服务器成功\n");acc_pass_t *p=(acc_pass_t*)malloc(sizeof(acc_pass_t));if(p==NULL){perror("malloc error");close(cfd);return -1;}memset(p,0,sizeof(acc_pass_t));int num;int logged_in=0;char current_account[20]={0}; while(1){if(!logged_in){printf("===== 请选择功能 =====\n");printf("1、注册账户\n");printf("2、登录账号\n");printf("3、退出程序\n");printf("======================\n");printf("选择功能:");scanf("%d",&num);switch(num){case 1:do_register(num,p,cfd);break;case 2:if(do_login(num,p,cfd) == 0){logged_in=1;strcpy(current_account,p->account); }break;case 3:printf("程序即将退出\n");free(p);close(cfd);return 0;default:printf("无效的选择,请重新输入\n");break;}}else{printf("===== 请选择功能 =====\n");printf("1、查找单词\n");printf("2、查找历史记录\n");printf("3、退出登录\n");printf("======================\n");printf("选择功能:");scanf("%d",&num);switch (num){case 1:do_search_word(cfd,current_account);break;case 2:do_search_history(cfd,current_account);break;case 3:do_logout(num,p,cfd);logged_in=0;memset(current_account,0,sizeof(current_account));printf("已退出登录\n");break;default:printf("无效的选择,请重新输入\n");break;}}}free(p);close(cfd);return 0;
}
3、现象

三、牛客网刷题
