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

2023-05-16

一、项目分析

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

                  

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

2、项目的流程

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

—  定义消息结构体;

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

—  编码实现;

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

3、客户端设计流程图:

4、服务器 流程图:

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

二、项目编码

1、服务端源码

#include "onlin_dic.h"
#include <sys/types.h>
#include <sqlite3.h>

#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 <sys/types.h>
#include <unistd.h>

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 <stdio.h>//perror();
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sqlite3.h>
#include <unistd.h>
#include <time.h>

#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

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言_网络编程_SQLite3数据库项目 _ 在线词典 的相关文章

随机推荐

  • linux下的环境变量

    环境变量 环境变量 xff0c 是指在操作系统中用来指定操作系统运行环境的一些参数 通常具备以下特征 xff1a 字符串 本质 有统一的格式 xff1a 名 61 值 值 值用来描述进程环境信息 存储形式 xff1a 与命令行参数类似 ch
  • 【004 关键字】extern “C“的作用是什么?

    一 extern 34 C 34 的作用 extern 34 C 34 关键字常用于C 43 43 和C混合编程中 xff0c 用于指定函数或变量采用C语言的命名和调用约定 加上extern 34 C 34 后 xff0c 会指示编译器这部
  • C++模板编程--学习C++类库的编程基础

    目录 一 函数模板二 类模板三 实现C 43 43 STL向量容器vector代码四 理解容器空间配置器allocator的重要性 一 函数模板 1 模板的意义 xff1a 对类型也可以进行参数化了 2 函数模板 lt 61 是不进行编译的
  • cmake 学习使用笔记(二)库的生成与使用

    学习使用cmake 生成及使用库 xff0c 使用cmake 生成 lib 静态库 及动态库 xff08 dll xff09 及linux 下使用的静态库 a 和 动态库 xff08 so 也称为共享库 xff09 目录 使用工具 生成库
  • cmake 学习使用笔记(五)手动编译

    目录 编译cmake 项目 构建 方式一 xff1a 可执行文件生成的在当前目录 方式二 xff1a 可执行文件生成只制定目录 记录一下手动编译 cmake 项目 编译cmake 项目 项目结构 注意 xff1a 必须要有一个 CMakeL
  • 四旋翼无人机学习第5节--STM32最小系统外围电路分析

    文章目录 1 芯片手册分析2 stm32的外部晶振手册分析2 stm32的外部上电复位手册分析3 电源放置方法4 GND放置方法5 其他元器件放置方法6 网络放置方法7 快捷键分享8 原理图绘制成果分享 快速使用芯片的最好的方式 xff0c
  • 现代C++单文件库(header only)

    nlohmann json https github com nlohmann json easyloggingpp https github com amrayn easyloggingpp
  • 一、ROS创建工作空间

    一 ROS创建工作空间 1 什么是工作空间2 创建工作空间3 编译工作空间4 创建功能包5 编译功能包 xff08 重新编译工作空间 xff09 6 设置环境变量7 运行节点 1 什么是工作空间 工作空间 xff08 workspace x
  • 二、ROS集成开发环境

    二 ROS集成开发环境 1 安装terminator2 安装VScode3 在VScode中使用ROS3 1 创建工作空间3 2 启动VScode3 3 配置VScode3 4 创建功能包3 5 编写C 43 43 文件3 6 配置CMak
  • 十一、Ubuntu18.04下VSCode配置C/C++编译环境

    十一 Ubuntu18 04下VSCode配置C C 43 43 编译环境 1 安装VSCode2 安装插件3 创建工程4 总结 1 安装VSCode 这一步就不谈了 2 安装插件 编译一些简单的cpp文件 xff0c 下面几个插件就够用了
  • 十五、Typora官方主题 + 自定义主题

    十五 Typora官方主题 43 自定义主题 1 下载官方主题2 在官方主题的基础上自定义 1 下载官方主题 首先去Typora官网下载自己喜欢的主题 xff1a 官方主题下载 例如我这里选择 Vue 我们只用到里面的两个主题文件vue c
  • linux---进程控制

    进程控制 fork函数 创建一个子进程 pid t fork void 失败返回 1 xff1b 成功返回 xff1a 父进程返回子进程的ID 非负 子进程返回 0 pid t vfork void 同样时创建一个子进程 xff0c 但是他
  • 十六、windows11下VSCode配置C/C++编译环境

    十六 windows11下VSCode配置C C 43 43 编译环境 1 安装VSCode2 中文插件3 MinGW编译器下载和配置4 VSCode配置c c 43 43 编译环境5 测试是否配置成功6 使用万能头文件 include l
  • 十七、WSL2的安装与使用(Win11)

    十七 WSL2的安装与使用 xff08 Win11 xff09 1 准备工作1 1 开启主板 BIOS 虚拟化1 2 检查是否成功开启虚拟化1 3 开启开发者模式1 4 开启所需Windows功能1 5 下载 WSL 内核升级包 2 开始安
  • 十八、Ubuntu20.04 + VSCode + Opencv3.4.16 配置 + WSL2 可视化

    十八 Ubuntu20 04 43 VSCode 43 Opencv3 4 16 配置 43 WSL2 可视化 1 下载和解压 OpenCV3 4 162 使用 cmake 编译 OpenCV3 配置环境4 代码测试4 1 录制视频4 2
  • IntelRealSense 更新D435固件时,运行rs-fw-update -l后报错:找不到命令

    环境 xff1a Ubantu18 04 摄像头 xff1a IntelRealsense D435 首先确定电脑里已经成功安装了 librealsense 想要更新下D435的固件 xff0c 但是运行rs fw update l后报错
  • Linux _ Shell编程 — 变量

    一 shell脚本的基础知识 1 shell脚本的本质 语言的分类有 xff1a 编译性语言 C语言 C 43 43 语言 JAVA PHP Python等 xff0c 不同编译器编译的执行文件不同 xff0c 运行的平台也不尽相同 解释性
  • USART _ 两串口同时使用,冲突问题

    1 使用外设情况 xff1a 1 初始化了两个串口 xff1a 串口1以及串口2 xff0c 使用串口2DMA发送数据 xff0c 接收中断 接收数据 xff1b 使用串口1发送函数发送数据 xff0c 接收中断接收数据 xff1b 2 问
  • C语言 _ MakeFile(一)

    一 Make简介 工程管理器 xff0c 顾名思义 xff0c 是指管理较多的文件 Make工程管理器也就是个 自动编译管理器 xff0c 这里的 34 自动 34 是指它能够根据文件时间戳自动发现更新过的文件而减少编译的工作量 xff0c
  • C语言_网络编程_SQLite3数据库项目 _ 在线词典

    一 项目分析 1 在线词典一般的饿运行过程 xff1a 例如 服务器端将用户信息和历史记录保存在数据库中 客户端输入用户和密码 xff0c 服务器端在数据库中查找 匹配 xff0c 返回结果 xff1b 2 项目的流程 定义数据库中表的结构