Level8 day1~3 在线词典项目

1.功能描述:

项目名称:在线英英词典

项目功能描述:

2. 项目流程分析

2.1 定义数据库中表的结构体

sqlite> .schema
CREATE TABLE usr(name text primary key , password text);
CREATE TABLE record (name text , date text, word text);

2.2 定义消息结构体

typedef struct {
	int type;
	char name[N];
	char data[256]; //password or word
} MSG;

2.3 服务器和客户端的流程图

.server:

.clietn:

3. 代码实现

.server:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>         
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include <sqlite3.h>
#include <errno.h>
#include <time.h>

#define SERV_PORT 5050
#define SERV_IP_ADDR "192.168.1.158"
#define FILEADDR "MyDictionary.db"
#define TABLE_USR "usr"
#define TABLE_RECORD "record"
#define SZ_DICT 512
#define R 1
#define L 2
#define Q 3         //Query_Word
#define H 4 		//History_Record
#define U 5 		//USR LIST
#define DONE -1
#define N 32

/*
 * 2020-10-08 by ku-yufeng
 * 在线辞典的服务端框架
 *
 *
 * */

typedef struct {
	int type;
	char name[N];
	char data[256]; //password or word
} MSG;

void do_register(int fd,MSG* msg,sqlite3* db);
int do_login(int fd, MSG* msg,sqlite3* db);
int do_query(int fd, MSG* msg,sqlite3* db);
int do_history(int fd, MSG* msg,sqlite3* db);
int sqlcallback(void *para, int f_num, char **f_value, char **f_name);
int do_searchword(char* word);
char* get_date();
int do_regRoot(sqlite3* db);
int do_userlist(int fd,MSG* msg,sqlite3* db);

int FLAG;
char NAME[N];
int SUPER_USR;

int main(int argc, const char *argv[])
{
	int fd,newfd;
	sqlite3* db;
	int result;
	ssize_t ret;
	MSG msg;
	pid_t pid;
	bzero((void*)&msg,sizeof(MSG));
	struct sockaddr_in mysockaddr;

	result = sqlite3_open(FILEADDR,&db);
	if(result != SQLITE_OK)
	{
		printf("%s\n",sqlite3_errmsg(db));
		return -1;
	}

	ret = do_regRoot(db); 		//创建 root 管理员账号 密码为1
	if(ret!=0)
		return -1;

	fd = socket(AF_INET,SOCK_STREAM,0);
	if(fd == -1)
	{
		perror("SOCKET");
		return -1;
	}

	bzero((void*)&mysockaddr,sizeof(struct sockaddr_in));
	mysockaddr.sin_family = AF_INET;
	mysockaddr.sin_port = htons(SERV_PORT);  //网络字节序的端口号

	result = inet_pton(AF_INET,SERV_IP_ADDR,(void*)&mysockaddr.sin_addr); 	//网络字节序的IP地址
	if(result != 1)
	{
		perror("inet_pton");
		return -1;
	}

	result = bind(fd,(struct sockaddr *)&mysockaddr,sizeof(struct sockaddr_in));
	printf("Server staring...OK!\n");
	if(result != 0)
	{
		perror("bind");
		close(fd);
		return -1;
	}
	signal(SIGCHLD,SIG_IGN); 	//不在意返回值,交由系统自动回收。防止产生僵尸进程。
	result = listen(fd,5);
	if(result!=0)
	{
		perror("listen");
		return -1;
	}
LOOP1:	
	newfd = accept(fd,NULL,NULL);

	if(newfd <0 ){
		perror("accept");
		return -1;
	}
	pid = fork();
	if(pid < 0)
	{
		perror("fork");
		return -1;
	}
	else if(0 == pid) 	//子进程
	{
		while(1)
		{
			do{
				ret = recv(newfd,(void*)&msg,sizeof(msg),0);
			}while(ret<0 && EINTR ==errno);
			if(ret<0)
			{
				perror("recv");
				return -1;
			}
			else if(!ret)
			{
				break;
			}
			printf("type: %d\n",msg.type);
			switch(msg.type)
			{
			case R:
				do_register(newfd, &msg,db);
				break;
			case L:
				do_login(newfd, &msg,db);
				break;
			case Q:
				do_query(newfd,&msg,db);
				break;
			case H:
				do_history(newfd,&msg,db);
				break;
			case U:
				do_userlist(newfd,&msg,db);
				break;
			default:printf("Invalid data msg\n");
			}
		}
		printf("client exit.\n");
		close(newfd);
	}
	else 	//父进程
	{
		goto LOOP1;	
	}

	return 0;
}	

void do_register(int fd,MSG* msg,sqlite3* db)
{
	char sql[500] = {0};
	char* errmsg;
	int result;
	sprintf(sql,"insert into %s values('%s','%s');",TABLE_USR,msg->name,msg->data);
	result = sqlite3_exec(db,sql,NULL,NULL,&errmsg);	
	if(result != SQLITE_OK)
	{
		printf("%s\n",sqlite3_errmsg(db));
		bzero((void*)msg,sizeof(MSG));
		strcpy(msg->data,"already exist");
		result = send(fd,msg,sizeof(MSG),0);
		return;
	}
	bzero((void*)msg,sizeof(MSG));
	strcpy(msg->data,"OK!");
	result = send(fd,msg,sizeof(MSG),0);
	printf("Register success!\n");
	return;
}
int do_login(int fd, MSG* msg,sqlite3* db)
{
	char sql[500] = {0};
	char* errmsg;
	int result;
	sprintf(sql,"select * from '%s' where name = '%s' and password = '%s';",TABLE_USR,msg->name,msg->data);
	printf("%s\n",sql);
	FLAG =0;
	result = sqlite3_exec(db,sql,sqlcallback,NULL,&errmsg);	
	if(result != SQLITE_OK || FLAG==0)
	{
		printf("%s\n",sqlite3_errmsg(db));
		bzero((void*)msg,sizeof(MSG));
		strcpy(msg->data,"usr/pwd wrony");
		result = send(fd,msg,sizeof(MSG),0);
		return -1;
	}
	strcpy(NAME,msg->name);
	if(!strcmp(NAME,"root"))
		SUPER_USR = 0; 		//管理员为0 普通用户为1
	else
		SUPER_USR = 1;
	bzero((void*)msg,sizeof(MSG));
	strcpy(msg->data,"OK!");
	result = send(fd,msg,sizeof(MSG),0);
	printf("Login success!\n");
	return 0;
}

int do_query(int fd, MSG* msg,sqlite3* db)
{
	int ret;
	char sql[500] = {0};
	char* errmsg;
	char* localtime;
	char word[256];

	strcpy(word,msg->data);
	ret = do_searchword(msg->data);
	printf("ret = %d, string = %s\n",ret,msg->data);
	if(ret == 1)
	{
		//返回查询到的数据到客户端
		ret = send(fd,msg,sizeof(MSG),0);
		printf("Success for search!\n");
		//存储查询记录
		localtime = get_date();
		localtime[strlen(localtime)-1] = 0;
		sprintf(sql,"insert into %s values('%s','%s','%s');",TABLE_RECORD,NAME,localtime,word);
		printf("%s\n",sql);

		ret = sqlite3_exec(db,sql,NULL,NULL,&errmsg);	
		if(ret != SQLITE_OK)
		{
			printf("%s\n",sqlite3_errmsg(db));
			return -1;
		}
	}
	else
	{
		bzero((void*)msg,sizeof(MSG));
		strcpy(msg->data,"not found!\n");
		ret = send(fd,msg,sizeof(MSG),0);
		printf("fail for search!\n");
	}
	return 0;
}

int do_history(int newfd, MSG* msg,sqlite3* db)
{
	char sql[500] = {0};
	char box[3][128] = {0};
	char* errmsg;
	char** pazResult;
	int nrow,ncolumn,sqlerr;
	int i,j,index;

	if(0 == SUPER_USR)
	{
		sprintf(sql,"select * from %s where name = '%s';",TABLE_RECORD,msg->name);
	}
	else if(1 == SUPER_USR)
	{
		sprintf(sql,"select * from %s where name = '%s';",TABLE_RECORD,NAME);
	}
	printf("sql:%s\n",sql);
	sqlerr = sqlite3_get_table(db,sql,&pazResult,&nrow,&ncolumn,&errmsg);
	if(sqlerr != SQLITE_OK){
		printf("%s\n",sqlite3_errmsg(db));
		return -1;
	}
	else{
		printf("Success for HISTORY\n");
		for(i=0,index=0;i<=nrow;i++){
			bzero((void*)box[0],128*3);
			for(j=0;j<ncolumn;j++,index++){
				sprintf(box[j],"%-32s",pazResult[index]);
				printf("%s",box[j]);
			}

			bzero((void*)msg,sizeof(MSG));
			sprintf(msg->data,"%s%s%s",box[0],box[1],box[2]);
			send(newfd,msg,sizeof(MSG),0);

			printf("\n");
		}
		bzero((void*)msg,sizeof(MSG));
		msg->type = DONE;
		send(newfd,msg,sizeof(MSG),0);
	}

	return 0;
}

int sqlcallback(void *para, int f_num, char **f_value, char **f_name)
{
	FLAG = 1;
	printf("f_num = %d\n",f_num);
	if(f_num <= 0)
	{
		return -1;
	}
	return 0;
}

int do_searchword(char* word)
{
	printf("进入serchword\n");
	FILE* fp;
	char botton[SZ_DICT];
	int ret;
	if((fp = fopen("dict.txt","r"))==NULL){
		printf("字典打开失败!\n");
		return 0;
	}
	while(fgets(botton,SZ_DICT,fp)!=NULL)
	{
		ret = strncmp(botton,word,strlen(word));
		if(ret < 0 )
		{
			bzero(botton,sizeof(botton));
			continue;
		}
		if(ret > 0 && botton[0]>='a' && botton[0]<'z')
		{
			//printf("无数据1\n");
			fclose(fp);
			return 0;
		}

		if(ret==0 && botton[strlen(word)] != ' ')
		{
			//printf("无数据2\n");
			fclose(fp);
			return 0;
		}
		if(ret==0)
		{
			//printf("%s\n",botton);
			bzero((void*)word,strlen(word));
			strncpy(word,botton,256);
			break;
		}
	}
	fclose(fp);
	return 1;
}

char* get_date()
{
	time_t timep;
	time(&timep);
	printf("%s",asctime(gmtime(&timep)));
	return asctime(gmtime(&timep));
}

int do_regRoot(sqlite3* db)
{
	char sql[500] = {0};
	char* errmsg;
	int result;
	sprintf(sql,"select * from '%s' where name = 'root' and password = '1';",TABLE_USR);
	printf("%s\n",sql);
	FLAG =0;
	result = sqlite3_exec(db,sql,sqlcallback,NULL,&errmsg);	
	if(result != SQLITE_OK)
	{
		printf("%s\n",sqlite3_errmsg(db));
		return -1;
	}
	if((FLAG == 0) && (SQLITE_OK == result))
	{
		sprintf(sql,"insert into %s values('root','1');",TABLE_USR);
		result = sqlite3_exec(db,sql,sqlcallback,NULL,&errmsg);	
		if(result != SQLITE_OK)
		{
			printf("%s\n",sqlite3_errmsg(db));
			return -1;
		}
	}

	return 0;
}

int do_userlist(int fd,MSG* msg,sqlite3* db)
{
	char sql[500] = {0};
	char box[2][N] = {0};
	char* errmsg;
	char** pazResult;
	int nrow,ncolumn,sqlerr;
	int i,j,index;

	printf("进入do_userlist!\n");
	sprintf(sql,"select * from %s;",TABLE_USR);
	sqlerr = sqlite3_get_table(db,sql,&pazResult,&nrow,&ncolumn,&errmsg);
	if(sqlerr != SQLITE_OK){
		printf("%s\n",sqlite3_errmsg(db));
		return -1;
	}
	else{
		printf("Success for HISTORY\n");
		for(i=0,index=0;i<=nrow;i++){
			bzero((void*)box[0],N*2);
			for(j=0;j<ncolumn;j++,index++){
			//	printf("%-31s",pazResult[index]);
				sprintf(box[j],"%-31s",pazResult[index]);
				printf("%s",box[j]);
			}

			bzero((void*)msg,sizeof(MSG));
			sprintf(msg->data,"%s%s",box[0],box[1]);
			send(fd,msg,sizeof(MSG),0);

			printf("\n");
		}
		bzero((void*)msg,sizeof(MSG));
		msg->type = DONE;
		send(fd,msg,sizeof(MSG),0);
	}
	return 0 ;
}

.clietn:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>         
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>

#define SERV_PORT 5050
#define SERV_IP_ADDR "192.168.1.158"
#define R 1         //Register
#define L 2 		//Login
#define Q 3         //Query_Word
#define H 4 		//History_Record
#define U 5 		//Usr List
#define DONE -1
#define N 32

/*
 * 2020-10-08 by ku-yufeng
 * 在线辞典的客户端框架
 *
 *
 * */

typedef struct {
	int type;
	char name[N];
	char data[256]; //password or word
} MSG;

void do_register(int fd,MSG* msg);
int do_login(int fd, MSG* msg);
int do_query(int fd, MSG* msg);
int do_history(int fd, MSG* msg);
int do_history_r(int fd, MSG* msg);

int main(int argc, const char *argv[])
{
	int fd;
	int result,cmd;
	MSG msg;
	bzero((void*)&msg,sizeof(MSG));
	struct sockaddr_in mysockaddr;

	fd = socket(AF_INET,SOCK_STREAM,0);
	if(fd == -1)
	{
		perror("SOCKET");
		return -1;
	}

	bzero((void*)&mysockaddr,sizeof(struct sockaddr_in));
	mysockaddr.sin_family = AF_INET;
	mysockaddr.sin_port = htons(SERV_PORT);  //网络字节序的端口号

	result = inet_pton(AF_INET,SERV_IP_ADDR,(void*)&mysockaddr.sin_addr); 	//网络字节序的IP地址
	if(result != 1)
	{
		perror("inet_pton");
		return -1;
	}
	printf("Client staring...OK!\n");

	result = connect(fd,(struct sockaddr *)&mysockaddr,sizeof(struct sockaddr_in));
	if(result != 0)
	{
		perror("connect");
		close(fd);
		return -1;
	}

	while(1)
	{
		printf("**************************************************\n");
		printf("* 1:Register         2:Login        3.Quit       *\n");
		printf("**************************************************\n");
		printf("please choose: ");
		scanf("%d",&cmd);
		setbuf(stdin,NULL);
		switch(cmd)
		{
		case 1: 
			do_register(fd,&msg);
			break;
		case 2:
			result = do_login(fd,&msg);
			if(result == 1)
			{
				goto next; 		//普通用户登陆的导航界面
			}
			if(result == 2)
			{
				goto next_r; 	//root用户登陆的导航界面
			}
			break;
		case 3:
			close(fd);
			exit(0);
			break;

		default:printf("CMD is illegal!\n");
		}
	}

next:
	while(1)
	{
		printf("**************************************************\n");
		printf("* 1:Query_Word     2:History_Record     3.Quit   *\n");
		printf("**************************************************\n");
		printf("please choose: ");
		scanf("%d",&cmd);
		switch(cmd)
		{
		case 1: do_query(fd,&msg);
				break;
		case 2: do_history(fd,&msg);
				break;
		case 3: close(fd);
				exit(0);
		default:printf("please select 1~3\n");cmd =0;
		}
		setbuf(stdin,NULL);
	}

next_r:
	while(1)
	{
		printf("**************************************************\n");
		printf("* WELCOME BACK MR.ROOT!                          *\n");
		printf("* 1:Query_Word     2:History_Record     3.Quit   *\n");
		printf("**************************************************\n");
		printf("please choose: ");
		scanf("%d",&cmd);
		switch(cmd)
		{
		case 1: do_query(fd,&msg);
				break;
		case 2: do_history_r(fd,&msg);
				break;
		case 3: close(fd);
				exit(0);
		default:printf("please select 1~3\n");cmd =0;
		}
		setbuf(stdin,NULL);
	}


	return 0;
}	

void do_register(int fd,MSG* msg)
{
	ssize_t ret;
	bzero((void*)msg,sizeof(MSG));
	printf("Set name please:");
	scanf("%s",msg->name);
	fflush(stdin);
	printf("Set password please:");
	scanf("%s",msg->data);
	fflush(stdin);

	msg->type = R;
	ret = send(fd,msg,sizeof(MSG),0);

	if(ret<0)
	{
		perror("send");
		return;
	}
	bzero(msg,sizeof(MSG));
	do{
		ret = recv(fd,msg,sizeof(MSG),0);
	}while(ret<0 && EINTR == errno);
	if(ret<0)
	{
		perror("recv");
		return;
	}
	else if(!ret)
	{
		printf("server exit.\n");
		exit(0);
	}

	ret = strcmp(msg->data,"OK!");
	if(!ret){
		printf("Register Success!\n");
	}
	else if(!strcmp(msg->data,"already exist")){
		printf("Register fail,name is exist!\n");
	}
	else{
		printf("不明错误原因,请与管理员联系\n");
	}

	return;
}

int do_login(int fd, MSG* msg)
{
	ssize_t ret;
	char name[N]={0};
	bzero((void*)msg,sizeof(MSG));
	printf("User name: ");
	scanf("%s",msg->name);
	setbuf(stdin,NULL);
	strcpy(name,msg->name);
	printf("PIN : ");
	scanf("%s",msg->data);
	setbuf(stdin,NULL);
	msg->type = L;

	ret = send(fd,msg,sizeof(MSG),0);

	if(ret<0)
	{
		perror("send");
		return 0;
	}
	bzero(msg,sizeof(MSG));
	do{
		ret = recv(fd,msg,sizeof(MSG),0);
	}while(ret<0 && EINTR == errno);
	if(ret<0)
	{
		perror("recv");
		return 0;
	}
	else if(!ret)
	{
		printf("server exit.\n");
		exit(0);
	}

	ret = strcmp(msg->data,"OK!");
	if(!ret){
		printf("Login Success!\n");
		if(!strcmp(name,"root"))
			return 2;
		return 1;
	}
	else{
		printf("USER/PIN Wrony!\n");
	}
	return 0;
}

int do_query(int fd, MSG* msg)
{
	ssize_t ret;
	bzero((void*)msg,sizeof(MSG));
	while(1)
	{
		printf("Set down a word,which you want to search('#' to quit...): ");
		scanf("%s",msg->data);
		setbuf(stdin,NULL);
		msg->type = Q;
		if(!strncmp(msg->data,"#",1))
		{
			printf("查询完毕...\n");
			return 0;
		}
		ret = send(fd,msg,sizeof(MSG),0);

		if(ret<0)
		{
			perror("send");
			return 0;
		}
		bzero(msg,sizeof(MSG));
		do{
			ret = recv(fd,msg,sizeof(MSG),0);
		}while(ret<0 && EINTR == errno);
		if(ret<0)
		{
			perror("recv");
			return 0;
		}
		else if(!ret)
		{
			printf("server exit.\n");
			exit(0);
		}
		printf("----------------------------------------------\n");
		printf("%s",msg->data);
		printf("----------------------------------------------\n");
	}
	printf("query word success!\n");
	return 0;
}

int do_history(int fd, MSG* msg)
{
	ssize_t ret;
	bzero((void*)msg,sizeof(MSG));
	msg->type = H;

	ret = send(fd,msg,sizeof(MSG),0);
	if(ret<0)
	{
		perror("send");
		return 0;
	}
	while(1)
	{
		bzero(msg,sizeof(MSG));
		do{
			ret = recv(fd,msg,sizeof(MSG),0);
		}while(ret<0 && EINTR == errno);
		if(ret<0)
		{
			perror("recv");
			return 0;
		}
		else if(!ret)
		{
			printf("server exit.\n");
			exit(0);
		}
		if(msg->type == DONE)
			break;
		printf("%s\n",msg->data);
	}
	return 0;
}

int do_history_r(int fd, MSG* msg)
{
	/* 打印用户名 供用户选择要查询记录的用户 */
	ssize_t ret;
	bzero((void*)msg,sizeof(MSG));
	msg->type = U;

	ret = send(fd,msg,sizeof(MSG),0);

	if(ret<0)
	{
		perror("send");
		return 0;
	}
	while(1)
	{
		bzero(msg,sizeof(MSG));
		do{
			ret = recv(fd,msg,sizeof(MSG),0);
		}while(ret<0 && EINTR == errno);
		if(ret<0)
		{
			perror("recv");
			return 0;
		}
		else if(!ret)
		{
			printf("server exit.\n");
			exit(0);
		}
		if(msg->type == DONE)
			break;
		printf("%s\n",msg->data);
	}

	/* 根据管理员选择的用户名 进行查询 */
	bzero((void*)msg,sizeof(MSG));
	msg->type = H;
	printf("Witch one do you want to search?\n");
	scanf("%s",msg->name);

	ret = send(fd,msg,sizeof(MSG),0);

	if(ret<0)
	{
		perror("send");
		return 0;
	}
	while(1)
	{
		bzero(msg,sizeof(MSG));
		do{
			ret = recv(fd,msg,sizeof(MSG),0);
		}while(ret<0 && EINTR == errno);
		if(ret<0)
		{
			perror("recv");
			return 0;
		}
		else if(!ret)
		{
			printf("server exit.\n");
			exit(0);
		}
		if(msg->type == DONE)
			break;
		printf("%s\n",msg->data);
	}


	return 0;
}

4. 使用的字典

本次使用的字典是 英-英 字典,与服务器端存储在同一文件夹下,文件名为:dict.txt
附链接:http://ku-yufeng.synology.me:5801/Linux/词典项目专用/

5. 效果演示:

5.1 普通用户登录:

linux@ubuntu:~/Level8/day3$ ./client 
Client staring...OK!
**************************************************
* 1:Register         2:Login        3.Quit       *
**************************************************
please choose: 1
Set name please:dashuaibi
Set password please:123
Register Success!
**************************************************
* 1:Register         2:Login        3.Quit       *
**************************************************
please choose: 2
User name: dashuaibi
PIN : 123
Login Success!
**************************************************
* 1:Query_Word     2:History_Record     3.Quit   *
**************************************************
please choose: 1
Set down a word,which you want to search('#' to quit...): dog
----------------------------------------------
dog              n.  common domestic animal kept by human beings for work, hunting, etc or as a pet
----------------------------------------------
Set down a word,which you want to search('#' to quit...): cat
----------------------------------------------
cat              n.  small furry domesticated animal often kept as a pet or for catching mice
----------------------------------------------
Set down a word,which you want to search('#' to quit...): #
查询完毕...
**************************************************
* 1:Query_Word     2:History_Record     3.Quit   *
**************************************************
please choose: 2
name                            date                            word                            
dashuaibi                       Wed Oct 14 09:23:25 2020        dog                             
dashuaibi                       Wed Oct 14 09:23:28 2020        cat                             
**************************************************
* 1:Query_Word     2:History_Record     3.Quit   *
**************************************************
please choose: 3
linux@ubuntu:~/Level8/day3$ 

5.2 管理员登录:

linux@ubuntu:~/Level8/day3$ ./client 
Client staring...OK!
**************************************************
* 1:Register         2:Login        3.Quit       *
**************************************************
please choose: 2
User name: root
PIN : 1
Login Success!
**************************************************
* WELCOME BACK MR.ROOT!                          *
* 1:Query_Word     2:History_Record     3.Quit   *
**************************************************
please choose: 2
name                           password                       
zhangsan                       123                            
lisi                           234                            
wangwu                         234                            
wangba                         123                            
zhaoba                         123                            
root                           1                              
dashuaibi                      123                            
Witch one do you want to search?
dashuaibi
name                            date                            word                            
dashuaibi                       Wed Oct 14 09:23:25 2020        dog                             
dashuaibi                       Wed Oct 14 09:23:28 2020        cat                             
**************************************************
* WELCOME BACK MR.ROOT!                          *
* 1:Query_Word     2:History_Record     3.Quit   *
**************************************************
please choose: 3
linux@ubuntu:~/Level8/day3$