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

news2024/9/22 21:22:44

一、项目要求

  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. 关闭文件描述符,关闭数据库
//导入词典
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. 关闭数据库
//匹配用户名是否存在
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. 关闭数据库
//实现登录功能
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. 关闭数据库
//插入记录
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. 关闭数据库
//查询记录
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);

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

#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);

		//另存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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/901529.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kestrel和ISS服务器下的配置

一、Kestrel服务器 Kestrel是ASP.NET Core框架中的一个跨平台的Web服务器。它是ASP.NET Core应用程序默认的HTTP服务器&#xff0c;并且可作为独立的Web服务器来托管ASP.NET Core应用程序。 Kestrel具有以下特点和功能 1、跨平台 Kestrel是完全跨平台的&#xff0c;可以在Wind…

git压缩/合并多次commit提交为1次commit提交

git压缩/合并N次commit提交为1次commit提交 假设有最近3次提交&#xff1a; commit_id1 commit_id2 commit_id3目标是把以上3次commit合并成1个commit&#xff0c;注意&#xff0c;最新的commit提交在最上面。 在git bash里面的操作步骤&#xff1a; &#xff08;1&#xff0…

Mac 开发 Tang Nano FPGA 指南(使用终端和使用 VS Code 和插件,适用所有 Gowin FPGA)

最近收到了一个 Tang nano 9K FPGA开发板&#xff0c;就想借此机会研究一下。 官方文档里介绍如果想使用高云的 FPGA&#xff0c;就需要使用 GOWIN IDE&#xff0c;但是需要申请 license 提交一堆资料&#xff0c;我是别人送的就不太方便让别人弄。加上 IDE 其实并不是很适合学…

QT SSL handshake failed问题分析与解决 QT基础入门【网络编程】openssl

问题: 使用https方式进行post 和get请求时,有时候会出现SSL handshake failed的问题,其实是调用Qt QNetworkAccessManager出现的问题。 其实SSL握手是建立HTTPS连接过程的第一步。为了验证和建立连接,用户的浏览器和网站的服务器必须经过一系列检查(握手),从而建立HTTP…

C++ 网络编程项目fastDFS分布式文件系统(五)--nginx+fastdfs

目录 1. 文件上传下载流程 2. Nginx和fastDFS的整合 3. 数据库表 3.1 数据库操 3.2 数据库建表 1. 文件上传下载流程 fileID 需要是一个哈希来判定。 2. 文件下载流程 3. 优化 优化思路 : 直接让客户端连接 fastDFS 的存储节点 , 实现文件下载 举例 , 访问一个…

AI重新定义音视频生产力“新范式”

// 编者按&#xff1a;AIGC无疑是当下的热门话题和场景。面对AI带来的技术变革和算力挑战&#xff0c;该如何应对&#xff1f;LiveVideoStackCon 2023上海站邀请到了网心科技副总裁武磊为我们分享网心在面对AI应用场景和业务需求下的实践经验。 文/武磊 编辑/LiveVideoStack …

泛型编程 学习笔记

#include "iostream"using namespace std;template<typename T> void Print(T a) {cout << a << endl; }int main() {int a 5;double b 2.3;char c e;string d "sdfasd";Print(a);Print(b);Print(c);Print(d);return 0; } 它可以不用…

关于springboot项目测试文件的目录结构

问题一 我在开发微服务项目的时候&#xff0c;有时候有些微服务是不需要启动类和配置文件的&#xff08;如xuechengService&#xff09;&#xff0c;这时候我们还需要在测试方法中进行测试&#xff0c;这时候我们可以将启动类放在测试类中&#xff0c;注意放在测试类中包的位置…

7-8 韩信点兵

分数 10 全屏浏览题目 切换布局 作者 颜晖 单位 浙大城市学院 在中国数学史上&#xff0c;广泛流传着一个“韩信点兵”的故事&#xff1a;韩信是汉高祖刘邦手下的大将&#xff0c;他英勇善战&#xff0c;智谋超群&#xff0c;为汉朝建立了卓越的功劳。据说韩信的数学水平也非…

Ctfshow web入门 权限维持篇 web670-web679 详细题解 全

CTFshow 权限维持 web670【】 补充一下PHP中单双引号的区别&#xff1a; 单引号和双引号之间最显着的区别在于我们插入字符串和变量时。单引号不插入字符串和变量。**单引号内的内容会按原样打印出来。**在大多数情况下&#xff0c;单引号内没有任何变量或转义序列的编译。 …

论文《LoRA: Low-Rank Adaptation of Large Language Models》阅读

论文《LoRA: Low-Rank Adaptation of Large Language Models》阅读 BackgroundIntroducitonProblem StatementMethodology Δ W \Delta W ΔW 的选择 W W W的选择 总结 今天带来的是由微软Edward Hu等人完成并发表在ICLR 2022上的论文《LoRA: Low-Rank Adaptation of Large Lan…

Java 日期格式(yyyy-MM-dd HH:mm:ss SSS)

常用格式为&#xff1a;yyyy-MM-dd HH:mm:ss 以 2019-12-31 06:07:59:666 时间为例&#xff1a; 字符 含义 Example y&#xff08;小写的y&#xff09; 年 yyyy---->2019 M&#xff08;大写的M&#xff09; 月 MM---->12 d&#xff08;小写的d&#xff09; 一…

使用Jmeter自带recorder代理服务器录制接口脚本

脚本录制 配置线程组 添加代理服务器 端口 和 录制脚本放置位置可根据需要设置 启动录制 点击启动后 弹出创建证书提示&#xff0c;点击OK 这个证书后续需要使用到 然后可见 一个弹窗。 Recorder . 本质是代理服务录制交易控制 可设置对应数据 方便录制脚本的查看 证书配置…

关于es中索引,倒排索引的理解

下面是我查询进行理解的东西 也就是说我们ES中的索引就相当于我们mysql中的数据库表&#xff0c;索引库就相当于我们的数据库&#xff0c;我们按照mapping规则会根据相应的字段&#xff08;index为true默认&#xff09;来创建倒排索引&#xff0c;这个倒排索引就相当于我们索引…

配置覆盖/获取追踪id

12 配置覆盖 提供了配置覆盖功能通过启动命令动态指定服务名&#xff0c;agent只需要部署一份。系统配置 -Dskywalking.agent.service_nameskywalking_mysql探针配置 指定jar包后&#xff0c;继续指定探针配置。系统环境变量覆盖优先级 探针配置>系统配置>系统环境变量&…

ONES × 鲁邦通|打造研发一体化平台,落地组织级流程规范

近日&#xff0c;ONES 签约工业互联网行业领先的解决方案提供商——鲁邦通&#xff0c;助力鲁邦通优化组织级流程规范&#xff0c;落地从需求到交付的全生命周期线上化管理。 依托于 ONES 一站式研发管理平台&#xff0c;鲁邦通在软硬件设计开发、项目管理和精益生产等方面的数…

企微配置回调服务

文章目录 一、简介1、概述2、相关文档地址 二、企微配置消息服务器1、配置消息接收参数2、参数解析3、参数拼接规则 三、代码编写—使用已有库1、代码下载2、代码修改3、服务代码编写 四、测试 一、简介 1、概述 什么时候需要回调服务 在集成企业微信与内部系统时&#xff0…

Spring 6.0官方文档示例(24): replace-method的用法

一、原始bean定义 package cn.edu.tju.study.service.anno.domain;public class MyValueCalculator {public String computeValue(String input) {return "you inputted: " input;}// some other methods... }二、replace bean定义 package cn.edu.tju.study.serv…

Win11中zookeeper的下载与安装

下载步骤 打开浏览器&#xff0c;前往 Apache ZooKeeper 的官方网站&#xff1a;zookeeper官方。在主页上点击"Project"选项&#xff0c;并点击"Release" 点击Download按钮&#xff0c;跳转到下载目录 在下载页面中&#xff0c;选择版本号&#xff0c;并点…

【王道-进程与线程】

#pic_center R 1 R_1 R1​ R 2 R^2 R2 目录 知识框架No.0 引言No.1 进程的概念、组成、特征一、进程的概念二、进程的组成1、PCB进程控制块2、程序段/数据段 三、程序是如何运行的&#xff1f;四、进程的特征五、总结 No.2 进程的状态转换和组织一、进程的状态1、创建态、就绪态…