项目——电子词典(客户端、服务器交互,字典导入,单词查询)

一、项目要求

  1. 登录注册功能,不能重复登录,重复注册
  2. 单词查询功能
  3. 历史记录功能,存储单词,意思,以及查询时间
  4. 基于TCP,支持多客户端连接
  5. 采用数据库保存用户信息与历史记录
  6. 将dict.txt的数据导入到数据库中保存。
  7. 按下ctrl+c退出客户端后,注销该客户端的登录信息

二、主要实现功能

  1. 注册
  2. 登录
  3. 查询单词
  4. 查询历史记录
  5. 退出登录

三、框架设计

3.1 服务器

3.2 客户端

四、功能实现

4.1 服务器实现功能代码

4.1.1 导入词典

主要流程:

  1. 创建并打开数据库
  2. 创建数据表
  3. 打开词典所在目录文件
  4. 逐行读取并插入到数据表中
  5. 关闭文件描述符,关闭数据库
cpp 复制代码
//导入词典
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 注册

主要流程:

  1. 创建并打开数据库
  2. 创建数据表
  3. 匹配来自客户端的用户名,若存在,则回复用户名已存在;若不存在,则将用户名与密码插入数据表中
  4. 关闭数据库
cpp 复制代码
//匹配用户名是否存在
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 登录

主要流程:

  1. 创建并打开数据库
  2. 创建数据表
  3. 匹配来自客户端的用户名和密码,若用户名和密码与数据库中的数据相匹配,则登录成功,否则登录失败
  4. 关闭数据库
cpp 复制代码
//实现登录功能
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 查找单词

主要流程:

  1. 创建并打开数据库
  2. 创建数据表
  3. 匹配来自客户端的单词,若存在,则返回查询结果并将查询记录插入到数据表中,若不存在,则查询失败
  4. 关闭数据库
cpp 复制代码
//插入记录
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 查找历史记录

主要流程:

  1. 创建并打开数据库
  2. 创建数据表
  3. 匹配当前登录的用户名,若存在记录,则返回记录信息,若不存在,则查找失败
  4. 关闭数据库
cpp 复制代码
//查询记录
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 客户端实现功能代码

cpp 复制代码
#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);

		//另存buf
		strcpy(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 头文件

cpp 复制代码
#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 功能函数

cpp 复制代码
#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 服务器

cpp 复制代码
#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 客户端

cpp 复制代码
#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);

		//另存buf
		strcpy(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;
}
相关推荐
JuiceFS24 分钟前
JuiceFS sync 原理解析与性能优化,企业级数据同步利器
运维·后端
Logan Lie1 小时前
Web服务监听地址的取舍:0.0.0.0 vs 127.0.0.1
运维·后端
Y淑滢潇潇2 小时前
RHCE 防火墙实验
linux·运维·rhce
wadesir2 小时前
当前位置:首页 > 服务器技术 > 正文Linux网络HSRP协议(实现路由器热备份与高可用性的实用指南)
linux·服务器·网络
稻谷君W2 小时前
Ubuntu 远程访问 Win11 WSL2 并固定访问教程
linux·运维·ubuntu
泡沫·2 小时前
4.iSCSI 服务器
运维·服务器·数据库
胡八一2 小时前
解决PHP未检测到您服务器环境的sqlite3数据库扩展报错
服务器·数据库·php
不解不惑3 小时前
OpenAI whisper 语音识别服务器搭建
服务器·whisper·语音识别
gaize12133 小时前
适合业务规模较大的场景的服务器测评
服务器
悠悠121383 小时前
告别Zabbix?我用Netdata只花10分钟就搞定了50台服务器的秒级监控(保姆级实战)
运维·服务器·zabbix