C语言_网络编程_SQLite3数据库项目 _ 在线词典

一、项目分析

1、在线词典一般的饿运行过程:例如

                  C语言_网络编程_SQLite3数据库项目 _ 在线词典_第1张图片

 —  服务器端将用户信息和历史记录保存在数据库中。客户端输入用户和密码,服务器端在数据库中查找、匹配,返回结果;

2、项目的流程

—  定义数据库中表的结构;

—  定义消息结构体;

—  分析服务器端和客户端 流程;

—  编码实现;

name text primary key : 表格中,name相同的 的字符串只能出现一次;

3、客户端设计流程图:

C语言_网络编程_SQLite3数据库项目 _ 在线词典_第2张图片

C语言_网络编程_SQLite3数据库项目 _ 在线词典_第3张图片

4、服务器 流程图:

C语言_网络编程_SQLite3数据库项目 _ 在线词典_第4张图片

C语言_网络编程_SQLite3数据库项目 _ 在线词典_第5张图片

— 总结: 在做任何的项目之前,都应该首先根据 项目需求 画出 流程图,根据流程图,编程时将更加有目的性;

二、项目编码

1、服务端源码

#include "onlin_dic.h"
#include 
#include 

#define DATABACK "my.db"
void cli_data_handle(int sockefd,sqlite3* db);
int do_searchword(sqlite3* db,_MSG *msg ,char word[]);//在文件中直接查找dict.txt

int do_register(int newfd , sqlite3* db , _MSG* msg)
{
	char *errmsg;
	char sql[128];

	sprintf(sql,"insert into usr values('%s','%s');",msg->name,msg->data);
	if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK)
	{
		printf("insert faile !!");
		strcpy(msg->data,"usr name already exist.");
	}else
	{
		printf("client register ok !\n");
		strcpy(msg->data,"ok");
	}
	if(send(newfd,msg,sizeof(_MSG),0) < 0)
	{
		printf("faile to faile");
		return -1;
	}
	return 1;
}

int do_history(int newfd , sqlite3* db , _MSG* msg)
{
	char sql[128];
	char history_word[255]= {0};
	int nrow;
	int ncloumn;
	char** resultp;
	char* errmsg;
	int index;
	int i,j;
	int index2;

	sprintf(sql,"select * from record where name = '%s';",msg->name);
	if(sqlite3_get_table(db,sql,&resultp,&nrow,&ncloumn,&errmsg) != SQLITE_OK )
	{
		printf("sqlite3_get_table faile !!");
	}else printf("sqlite3_get_table ok\n");//根据用户名以及密码,查找返回查找过得相应的记录

	index = 0;//列数
	for(i = 0;i<=nrow;i++)//行数
	{
		for(j = 0;j<=ncloumn;j++)
		{
			index2 = index;
			printf("%s  ",resultp[index++]);
			strcat(history_word,resultp[index2]);
			strcat(history_word,"  ");
		}
		strcat(history_word,"\r\n");
		printf("\n");
	}
	strcpy(msg->data,history_word);
	if(send(newfd,msg,sizeof(_MSG),0) < 0)
	{
		printf("To %s send faile !!",msg->name);
		return -1;
	}
	printf("%d \n",strlen(msg->data));
	return 1;
}

int do_login(int newfd , sqlite3* db , _MSG* msg)
{
	char sql[128];
	char *errmsg;
	int nrow;
	int ncloumn;
	char** resultp;
	int flag = -1;

	sprintf(sql,"select * from usr where name = '%s'and pass = '%s';",msg->name,msg->data);
	if(sqlite3_get_table(db,sql,&resultp,&nrow,&ncloumn,&errmsg) != SQLITE_OK )
	{
		printf("%s",errmsg);
		return flag;
	}else printf("sqlite3_get_table ok");
	//查询成功,数据库中拥有此用户
	if(nrow == 1)
	{
		flag = 1;
		printf("query ok\n");
		strcpy(msg->data,"ok");
	}else//查询错误 用户名或密码错误
	{
		flag = -1;
		printf("query faile \n");
		strcpy(msg->data,"usr or pass wrong !");
	}
	if(send(newfd,msg,sizeof(_MSG),0) < 0)
	{
		printf("faile to send");
		return -1;
	}
	return flag;
}

int do_query(int newfd , sqlite3* db , _MSG* msg)
{
	int found;
	char word[64];
	char sql[128];
	char* errmsg;
	char timedata[64];
	time_t t;
	struct tm *tp;
	char name[32];

	strcpy(name,msg->name);
	strcpy(word,msg->data);
	printf("Client %s query_word %s \n",msg->name,word);
	found = do_searchword(db,msg,word);
	if(found == 1)//如果查找成功了,则数据、查找时间,用户等信息存入数据库
	{
		time(&t);
		tp = localtime(&t);
		sprintf(timedata,"%d-%02d-%02d %02d:%02d:%02d",tp->tm_year+1900,tp->tm_mon+1,tp->tm_mday,tp->tm_hour,tp->tm_min,tp->tm_sec);
		sprintf(sql,"insert into record values('%s','%s','%s');",name,word,timedata);
		if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) < 0)
		{
			perror("sqlite3_exec");
			strcpy(msg->data,"sqlite3_exec NO found");
		}else
		{
			printf("query success !!!\n");
		}
	}else
	{
		strcpy(msg->data,"NO found !\n");//查找失败了
	}
	if(send(newfd,msg,sizeof(_MSG),0) < 0)
	{
		printf("send to faile !!!");
		return -1;
	}
	return 1;
}
int do_searchword(sqlite3* db,_MSG *msg ,char word[])//在文件中直接查找dict.txt
{
	FILE *fp;
	int len = 0;
	char buf[512] = {};
	int result;
	char *p;

	if((fp = fopen("dict.txt","r")) ==NULL )
	{
		perror("fopen");
		return -1;
	}
	//打印出,客户端要查寻的单词
	len = strlen(word);
	printf("%s   len = %d \n",word,len);

	//按行读文件,来查询单词
	while(fgets(buf,512,fp) != NULL)//从指定的文件一行一行的读出数据
	{
		result = strncmp(buf,word,len);
		if(result == 0 && buf[len] == ':')
		{	
			p = buf + len ;
			//找到之后
			strcpy(msg->data,p);
			fclose(fp);
			return 1;
		}else
		{
			continue;
		}
	}
				
	fclose(fp);
	return 0;
}

int main(int argc, const char *argv[])
{
	sqlite3 * db;
	int sockefd;
	struct sockaddr_in sin;
	int port = 0;
	char * errmsg;

	if(argc < 3)
	{
		printf("Usage : %s  ServerIP  ServerPort \n",argv[0]);
		printf("ServerIP: server ip  addr !!!");
		printf("ServerPort: server port !!!!");
		exit(1);//异常退出
	}

	/*0 、创建,打开数据库*/
	if(sqlite3_open(DATABACK,&db) != SQLITE_OK)
	{
		printf("%s \n",sqlite3_errmsg(db));
		return -1;
	}else{
		printf("DATABACK db success !!!\n");
	}
	/*创建表格*/
	if(sqlite3_exec(db,"create table usr(name text primary key ,pass text);",NULL,NULL,&errmsg) != SQLITE_OK)
	{
		printf("usr 已存在\n"); 
	}else 
	{
		printf("create usr success !!\n");
	}
	if(sqlite3_exec(db,"create table record(name text,word text,time text);",NULL,NULL,&errmsg) != SQLITE_OK)
	{
		printf("record 已存在\n");
	}else 
	{	
		printf("create record success !!!\n");
	}

 	port = atoi(argv[2]);

	/*1、 socket()创建 文件描述符 */
	if((sockefd = socket(AF_INET, SOCK_STREAM , 0)) < 0)
	{
		perror("socket");
		exit(1);
	}
#if 0
	/*优化:可立即绑定在 任何服务器IP上*/
	if( socketopt() < 0)
	{

	}
#endif
	/*2、绑定 */
	/*2.1 、 填充 结构体sockaddr_in*/
	bzero(&sin,sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_port = htons(port);
	if(inet_pton(AF_INET,argv[1],(void*)&sin.sin_addr) == -1)
	{
		perror("inet_pton");
	printf("Server Starting!!!   ip: %s port: %s \n",argv[1],argv[2]);
		exit(1);
	}
	/*2.2 int  bind(int sockefd,const struct sockaddr *addr ,socklen_t addrlen) 绑定*/
	if(bind(sockefd,(struct sockaddr*)&sin,sizeof(sin)) < 0 )
	{
		perror("bind");
		exit(1);
	}
	/*3、使用listen(int sockfd , int backlog) 将主动套接字 改为 被动套接字*/
	if(listen(sockefd,5) < 0)//将套接字设置为监听模式
	{
		perror("listen");
		exit(1);
	}
	printf("Server Starting!!!   ip: %s port: %s \n",argv[1],argv[2]);
	int newfd = -1;
	while(1)
	{
		pid_t pid = -1;
		newfd = accept(sockefd ,NULL,NULL);
		if(newfd < 0)
		{
			perror("accept");
			exit(1);
		}
		if((pid = fork()) < 0)
		{
			perror("fork");
			break;
		}else if(pid == 0)//子进程
		{
			close(sockefd);
			cli_data_handle(newfd,db);
			return 0;
		}else //父进程 
		{
			close(newfd);
		}
	}
	close(sockefd);
	return 0;
} 

void cli_data_handle(int sockefd,sqlite3* db)
{
	 int newfd = sockefd;
	 static _MSG msg;
	
	while(recv(newfd,&msg,sizeof(_MSG),0))
	{
		switch(msg.type)
		{
		case R:
			printf("recv client register(注册) data:%d  \n",msg.type);
			do_register(newfd,db,&msg);
			break;
		case L:
			printf("recv client login(登录) data:%d \n",msg.type);
			if(do_login(newfd ,db,&msg))printf("%s login success\n",msg.data);
			break;
		case H:
			printf("recv client %s history(查询历史记录) data:%d \n",msg.name,msg.type);
			do_history(newfd,db,&msg);
			break;
		case Q:
			printf("recv client %s query(查询单词) data:%d \n",msg.name,msg.type);
			do_query(newfd,db,&msg);
			break;
		default:
			printf("Invalid data msg. \n");
		}
	}
	close(newfd);
	exit(0);
	return;	
}

2、客户端代码

#include "onlin_dic.h"
#include 
#include 

int do_register(int sockfd,_MSG *msg)
{
	msg->type = R;
	printf("input name (输入注册姓名):");
	scanf("%s",msg->name);
	getchar();//去除无用字符

	printf("input pass(输入登录密码):");
	scanf("%s",msg->data);
	getchar();

	printf("name :%s   pass:%s  \n",msg->name,msg->data);
	//ssize_t send(int sockfd,const void* buf,size_t len , int flags)
	if(send(sockfd,msg,sizeof(_MSG),0) < 0)//发送注册信息给服务器
	{
		printf("faile to send !\n");
		return -1;
	}
	if(recv(sockfd,msg,sizeof(_MSG),0) < 0)
	{
		printf("Faile to recv !\n");
		return -1;
	}
	return 0;
}

int do_logic(int sockfd , _MSG *msg)
{
	msg->type = L;
	printf("input name (输入姓名):");
	scanf("%s",msg->name);
	getchar();//去除无用字符

	printf("input pass(输入密码):");
	scanf("%s",msg->data);
	getchar();

	printf("登录信息:name :%s   pass:%s  \n",msg->name,msg->data);
	//ssize_t send(int sockfd,const void* buf,size_t len , int flags)
	if(send(sockfd,msg,sizeof(_MSG),0) < 0)//发送注册信息给服务器
	{
		printf("faile to send !\n");
		return -1;
	}
	if(recv(sockfd,msg,sizeof(_MSG),0) < 0)
	{
		printf("Faile to recv \n!");
		return -1;
	}
	if(strncmp(msg->data,"ok",sizeof("ok")) == 0)
	{
		printf("%s login %s \n",msg->name,msg->data);
		return 1;
	}else
	{
		printf("%s login %s \n",msg->name,msg->data);
	}
	printf("接受服务器回复信息:%s \n",msg->data);
	return 0;
}

void do_query_word(int sockfd,_MSG *msg)
{
	msg->type = Q;
	while(1)
	{
		printf("Input query_word(输入需要查询的单词,**退出) :");
		scanf("%s",msg->data);
		getchar();

		if(strncmp(msg->data,"**",strlen("**")) == 0)
		{
			break;
		}
		if(send(sockfd,msg,sizeof(_MSG),0) < 0)
		{
			perror("send");
			continue;
		}
		if(recv(sockfd,msg,sizeof(_MSG), 0) < 0)
		{
			perror("recv");
			continue;
		}
		printf("%s",msg->data);
	}
	return;
}

void do_hostoty_recoyd(int sockfd,_MSG* msg)
{
	msg->type = H;
	
	if(send(sockfd,msg,sizeof(_MSG),0) < 0)
	{
		perror("send");
		return;
	}
	if(recv(sockfd,msg,sizeof(_MSG),0) < 0)
	{
		perror("recv");
		return;
	}
	printf("hostory_recoyd:\n%s \n",msg->data);
	return;
}

int do_next_ui(int sockfd , _MSG *msg)
{
	int m;
	while(1)
	{
		printf("*********************************************************************************\n");
		printf("/*1:query_word(查询单词) 2:hostory_recoyd(历史记录) 3:quit(返回上级菜单)*/\n");
		printf("*********************************************************************************\n");
		printf("input(请输入命令) :");
		m = 0;
		
		scanf("%d",&m);
		if(m<0 && m> 9)continue;
		getchar();
		switch(m)
		{
			case 1:
				do_query_word(sockfd,msg);
				break;
			case 2:
				do_hostoty_recoyd(sockfd,msg);
				break;
			case 3:
				return 0;
			default:
				printf("输入有误!!!\n");
		}
	}
	return 0;
}

int main(int argc, const char *argv[])
{
	int sockfd;
	struct sockaddr_in sin;
	_MSG msg;
	int port;
	int n;
	
	if(argc < 3)
	{
		printf("Usage : %s ServerIP  ServerPort \n",argv[0]);
		printf("ServerIP : server ip addr \n");
		printf("ServerPort: server port (>5000)\n");
		exit(0);
	}
	port = atoi(argv[2]);//字符串 转整数
/*1、socket(int domain , int type , int protocol ) 生成特殊的文件描述符*/
	if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1 )
	{
		perror("socket");
		exit(1);//异常退出
	}
/*2、填充 sockaddr_in 结构体*/
	/*2.1 填充结构体*/
	bzero(&sin,sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_port = htons(port);
	/*int inet_pton(int af,const char * src , void *dst)*/
	if(inet_pton(AF_INET,argv[1],(void*)&sin.sin_addr) == -1)
	{
		perror("inet_pton");
		exit(1);
	}
/*3 连接int connect(int sockfd , const struct sockaddr *addr,socklen_t
	 * addrlen)*/
	if(connect(sockfd , (struct sockaddr*)&sin,sizeof(sin)) < 0 )
	{
		perror("connect");
		exit(1);
	}
	while(1)
	{
		bzero(&msg,sizeof(_MSG));
		printf("**************************************************\n");
		printf("/*1:register(注册) 2:login(登录) 3:quit(退出字典)*/\n");
		printf("**************************************************\n");
		printf("input(请输入命令) :");
		n = 0;
		bzero(&msg,sizeof(_MSG));
		scanf("%d",&n);
		switch(n)
		{
			case 1:
				do_register(sockfd,&msg);
				break;
			case 2:
				if(do_logic(sockfd,&msg) == 1)
				{
					do_next_ui(sockfd,&msg);
				}
				break;
			case 3:
				close(sockfd );
				exit(0);
			default:
				printf("input error(输入错误,请重新输入) !!\n");
				break;
		}
	}
	close(sockfd);
	return 0;
}

3、所使用的头文件

#ifndef _ONLIN_DIC_H__
#define _ONLIN_DIC_H__

#include //perror();
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define N 32 
#define L 1
#define R 2
#define Q 3
#define H 4

typedef struct {
	int type;
	char name[N];
	char data[255];//password or word
}_MSG;
#endif

 

 

你可能感兴趣的:(Linux,_,嵌入式网络)