lv10 嵌入式开发 在线英英词典

news2024/11/26 6:23:32

1 有道词典流程分析及本项目功能描述

1.1 抽取项目原理分析 

本项目功能描述

  • 用户注册和登录验证
  • 服务器端将用户信息和历史记录保存在数据库中。客户端输入用户名和密码,服务器端在数据库中查找、匹配,返回结果
  • 单词在线翻译
  • 根据客户端输入的单词在字典文件中搜索
  • 历史记录查询

1.2 项目流程

  • 定义数据库中表的结构
  • 定义消息结构体
  • 分析服务端与客户端流程
  • 编码实现

表结构

        usr表

        name(primary key) passwd

        record表

        name date word

        单词表

        使用文件查询,如使用数据库的话代码会更简单

消息结构体

#define   N  32

#define  R  1   // user - register
#define  L  2   // user - login
#define  Q  3   // user - query
#define  H  4   // user - history

// 定义通信双方的信息结构体
typedef struct {
	int type;
	char name[N];
	char data[256];
}MSG;

1.3 客户端流程分析

连接服务端

一级菜单提示:1注册 2登录 3退出

如果登录成功,跳转至二级菜单

二级菜单提示:1查询 2历史 3退出 #返回上级菜单

分别实现对应功能

1.4 服务端流程分析

2 代码开发

2.1 客户端开发

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

#define N 32
#define R 1   //注册
#define L 2   //登录
#define Q 3   //查询单词
#define H 4   //历史

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



int do_register(int sockfd, MSG_t *msg);
int do_login(int sockfd, MSG_t *msg);
int do_query(int sockfd, MSG_t *msg);
int do_history(int sockfd, MSG_t *msg);



int main(int argc, char *argv[])
{
	int sockfd;
	int n;
	struct sockaddr_in addr;
	MSG_t msg;

	bzero(&msg, sizeof(MSG_t));

	//参数检查
	if(argc != 3)
	{
		printf("%s <ip> <port>\n",argv[0]);
		exit(0);
	}

	//创建socket
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if(sockfd < 0)
	{
		perror("socket");
		exit(0);
	}

	//连接connect
	addr.sin_family = AF_INET;
	addr.sin_port = htons(atoi(argv[2]));
	addr.sin_addr.s_addr = inet_addr(argv[1]);

	if(connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
	{
		perror("connect");
		exit(0);
	}

	while(1)
	{
		printf("***********************************\n");
		printf("*1:register    2:login    3:quit  *\n");
		printf("***********************************\n");
		printf("Please choose:");
		scanf("%d", &n);

		switch(n)
		{
			case 1:
				do_register(sockfd, &msg);
				break;
			case 2:
				if(do_login(sockfd, &msg) == 1)
				{
					goto next;
				}
				break;
			case 3:
				close(sockfd);
				exit(0);
		}
	}
next:
		while(1)
		{
			printf("***********************************\n");
			printf("*1:search    2:history    3:quit  *\n");
			printf("***********************************\n");
			printf("Please choose:");
			scanf("%d", &n);

			switch(n)
			{
			case 1:
				do_query(sockfd, &msg);
				break;
			case 2:
				do_history(sockfd, &msg);
				break;
			case 3:
				close(sockfd);
				exit(0);
			case 4:
				break;
			}
		}
	
	return 0;

}


int do_register(int sockfd,MSG_t *msg)
{
	msg->type = R;
	

	printf("Input name:");
	scanf("%s", msg->name);
	getchar();

	printf("Input passwd:");
	scanf("%s", msg->data);


	if(write(sockfd, msg, sizeof(MSG_t)) < 0)
	{
		perror("write");
		return -1;
	}

	if(read(sockfd, msg, sizeof(MSG_t)) < 0)
	{
		perror("read");
		return -1;
	}

	//成功或者用户已经注册
	printf("%s\n", msg->data);
	return 0;
}

int do_login(int sockfd, MSG_t *msg)
{
	msg->type = L;


	printf("Input name:");
	scanf("%s", msg->name);
	getchar();

	if(strcmp(msg->name, "root") == 0)
	{
		msg->root_flag = 1;
	}
	else
	{
		msg->root_flag = 0;
	}

	printf("Input passwd:");
	scanf("%s", msg->data);


	if(send(sockfd, msg, sizeof(MSG_t), 0) < 0)
	{
		perror("write");
		return -1;
	}
	
	if(recv(sockfd, msg, sizeof(MSG_t), 0) < 0)
	{
		perror("read");
		return -1;
	}

	if(strncmp(msg->data, "OK", 3) == 0)
	{
		printf("Login success.\n");
		return 1;
	}
	else
	{
		printf("%s\n",msg->data);
	}

	return 0;
}

int do_query(int sockfd,MSG_t *msg)
{
	msg->type = Q;
	printf("--------------------------\n");

	while(1)
	{
		printf("Input word:");
		scanf("%s",msg->data);
		getchar();

		//输入#返回上级菜单
		if(strncmp(msg->data, "#", 1) == 0)
		{
			break;
		}

		if(write(sockfd, msg, sizeof(MSG_t)) < 0)
		{
			perror("write");
			return -1;
		}

		if(read(sockfd, msg, sizeof(MSG_t)) < 0)
		{
			perror("read");
			return -1;
		}

		printf("%s\n",msg->data);
	}
	return 0;
}

int do_history(int sockfd, MSG_t *msg)
{

	msg->type = H;

	if(write(sockfd, msg, sizeof(MSG_t)) < 0)
	{
		perror("write");
		return -1;
	}

	while(1)
	{
		if(read(sockfd, msg, sizeof(MSG_t)) < 0)
		{
			perror("read");
			return -1;
		}
		if(msg->data[0] == '0')
			break;

		printf("%s\n",msg->data);
	}
	return 0;
}

2.2 服务端开发

表设计,创建usr表用于管理登录,创建record表用于记录查询历史

linux@linux:~/Desktop/dictionary$ sqlite3 my.db
SQLite version 3.8.2 2013-12-06 14:53:30
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .database
seq  name             file                                                      
---  ---------------  ----------------------------------------------------------
0    main             /home/linux/Desktop/dictionary/my.db                      
sqlite> create table usr(name text, passwd text);
sqlite> create table record(name text, date text, word text);
sqlite> :q

代码设计,接收客户端后fork出子进程,用于多客户端连接使用

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

#define N 32

#define R 1  //register
#define L 2  //login
#define Q 3  //query
#define H 4  //history

#define DATABSAE "my.db"

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

int do_client(int acceptfd, sqlite3 *db);
void do_register(int acceptfd, MSG_t *msg, sqlite3 *db);
int do_login(int acceptfd, MSG_t *msg, sqlite3 *db);
int do_query(int acceptfd, MSG_t *msg, sqlite3 *db);
int do_history(int acceptfd, MSG_t *msg,sqlite3 *db);
int history_callback(void *arg, int f_num, char **f_value, char **f_name);
int do_searchword(int acceptfd, MSG_t *msg, char word[]);
int get_date(char *date);



int main(int argc, char *argv[])
{
	int sockfd;
	int acceptfd;

	struct sockaddr_in serveraddr;
	MSG_t msg;
	sqlite3 *db;
	pid_t pid;

	bzero(&msg, sizeof(MSG_t));

	//参数检查
	if(argc != 3)
	{
		printf("%s <ip> <port>\n",argv[0]);
		exit(0);
	}

	//打开数据库
	if(sqlite3_open(DATABSAE, &db) != SQLITE_OK)
	{
		printf("%s\n",sqlite3_errmsg(db));
		exit(0);
	}
	else
	{
		printf("open DATABSAE success.\n");
	}

	//创建socket
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if(sockfd < 0)
	{
		perror("socket");
		exit(0);
	}

	//绑定bind
	bzero(&serveraddr,sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_port = htons(atoi(argv[2]));
	serveraddr.sin_addr.s_addr = inet_addr(argv[1]);

	if(bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
	{
		perror("bind");
		exit(0);
	}

	//监听listen
	if(listen(sockfd, 5) < 0)
	{
		printf("listen");
		exit(0);
	}

	//处理僵尸进程
	signal(SIGCHLD, SIG_IGN);

	while(1)
	{
		if((acceptfd = accept(sockfd, NULL, NULL)) < 0)
		{
			perror("accept");
			exit(0);
		}

		if((pid = fork()) < 0)
		{
			perror("fork");
			exit(0);
		}
		else if(pid == 0)     //儿子进程
		{
			//处理客户端具体的消息
			close(sockfd);
			do_client(acceptfd, db);
		}
		else                  //父进程
		{
			close(acceptfd);
		}
	}
	return 0;

}

int do_client(int acceptfd, sqlite3 *db)
{
	MSG_t msg;
	while(read(acceptfd, &msg, sizeof(msg)) > 0)
	{
		printf("type:%d\n",msg.type);
		switch(msg.type)
		{
		case R:
			do_register(acceptfd, &msg, db);
			break;
		case L:
			do_login(acceptfd, &msg, db);
			break;
		case Q:
			do_query(acceptfd, &msg, db);
			break;
		case H:
			do_history(acceptfd, &msg, db);
			break;
		default:
			printf("Invalid data msg.\n");
		}
	}

	printf("client exit.\n");
	close(acceptfd);
	exit(0);

	return 0;
}

void do_register(int acceptfd, MSG_t *msg, sqlite3 *db)
{
	char * errmsg;
	char sql[128];

	sprintf(sql, "insert into usr values('%s', %s);", msg->name, msg->data);
	printf("%s\n", sql);

	if(sqlite3_exec(db,sql, NULL, NULL, &errmsg) != SQLITE_OK)
	{
		printf("%s\n", errmsg);
		strcpy(msg->data, "usr name already exist.");
	}
	else
	{
		printf("client  register ok!\n");
		strcpy(msg->data, "OK!");
	}

	if(send(acceptfd, msg, sizeof(MSG_t), 0) < 0)
	{
		perror("fail to send");
		return ;
	}

	return ;
}

int do_login(int acceptfd, MSG_t *msg , sqlite3 *db)
{
	char sql[128] = {};
	char *errmsg;
	int nrow;
	int ncloumn;
	char **resultp;

	sprintf(sql, "select * from usr where name = '%s' and passwd = '%s';", msg->name, msg->data);
	printf("%s\n", sql);

	if(sqlite3_get_table(db, sql, &resultp, &nrow, &ncloumn, &errmsg)!= SQLITE_OK)
	{
		printf("%s\n", errmsg);
		return -1;
	}
	else
	{
		printf("get_table ok!\n");
	}

	// 查询成功,数据库中拥有此用户
	if(nrow == 1)
	{
		strcpy(msg->data, "OK");
		send(acceptfd, msg, sizeof(MSG_t), 0);
		return 1;
	}

	if(nrow == 0) // 密码或者用户名错误
	{
		strcpy(msg->data,"usr/passwd wrong.");
		send(acceptfd, msg, sizeof(MSG_t), 0);
	}

	return 0;
}

int do_searchword(int acceptfd, MSG_t *msg, char word[])
{
	FILE * fp;
	int len = 0;
	char temp[512] = {};
	int result;
	char *p;


	//打开文件,读取文件,进行比对
	
	if((fp = fopen("dict.txt", "r")) == NULL)
	{
		perror("fail to fopen.\n");
		strcpy(msg->data, "Failed to open dict.txt");
		send(acceptfd, msg, sizeof(MSG_t), 0);
		return -1;
	}

	//打印出,客户端要查询的单词
	len = strlen(word);
	printf("%s , len = %d\n", word, len);

	//读文件,来查询单词
	while(fgets(temp, 512, fp) != NULL)  //每次读取512字节
	{

	//	printf("temp:%s\n", temp);

		// abandon  ab
		result = strncmp(temp,word,len);  

		if(result < 0)  //不相等
		{
			continue;
		}                
		if(result > 0 || ((result == 0) && (temp[len]!=' ')))  //第一个字符串>第二个或者两者相同但后面不是空格,表示在注释里出现的单词
		{
			break;
		}

		// 表示找到了,查询的单词result == 0 且 temp[len] == ' '。
		p = temp + len; //  abandon   v.akdsf dafsjkj 
	//	printf("found word:%s\n", p);
		while(*p == ' ')
		{
			p++;
		}
		// 找到了注释,跳跃过所有的空格

		strcpy(msg->data, p);
		printf("found word:%s\n", msg->data);

		// 注释拷贝完毕之后,应该关闭文件
		fclose(fp);
		return 1;
	}

	fclose(fp);

	return 0;
}

int get_date(char *date)
{
	time_t t;
	struct tm *tp;

	time(&t);

	//进行时间格式转换
	tp = localtime(&t);

	sprintf(date, "%d-%d-%d %d:%d:%d", tp->tm_year + 1900, tp->tm_mon+1, tp->tm_mday, 
			tp->tm_hour, tp->tm_min , tp->tm_sec);
	printf("get date:%s\n", date);

	return 0;
}

int do_query(int acceptfd, MSG_t *msg , sqlite3 *db)
{
	char word[64];
	int found = 0;
	char date[128] = {};
	char sql[128] = {};
	char *errmsg;

	//拿出msg结构体中,要查询的单词
	strcpy(word, msg->data);

	found = do_searchword(acceptfd, msg, word);
	printf("查询一个单词完毕.\n");

	// 表示找到了单词,那么此时应该将 用户名,时间,单词,插入到历史记录表中去。
	if(found == 1)
	{
		// 需要获取系统时间
		get_date(date);

        sprintf(sql, "insert into record values('%s', '%s', '%s')", msg->name, date, word);

		if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
		{
			printf("%s\n", errmsg);
			return -1;
		}
		else
		{
			printf("Insert record done.\n");
		}

	}
	else  //表示没有找到
	{
		strcpy(msg->data, "Not found!");
	}

	// 将查询的结果,发送给客户端
	send(acceptfd, msg, sizeof(MSG_t), 0);

	return 0;
}

// 得到查询结果,并且需要将历史记录发送给客户端
int history_callback(void* arg,int f_num,char** f_value,char** f_name)
{
	// record  , name  , date  , word 
	int acceptfd;
	MSG_t msg;

	acceptfd = *((int *)arg);

	sprintf(msg.data, "%s , %s", f_value[1], f_value[2]);

	send(acceptfd, &msg, sizeof(MSG_t), 0);

	return 0;
}


int do_history(int acceptfd, MSG_t *msg, sqlite3 *db)
{
	char sql[128] = {};
	char *errmsg;
	
	if(msg->root_flag == 1)
	{
		sprintf(sql, "select * from record");	
	}
	else
	{
		sprintf(sql, "select * from record where name = '%s'", msg->name);
	}

	//查询数据库
	if(sqlite3_exec(db, sql, history_callback,(void *)&acceptfd, &errmsg)!= SQLITE_OK)
	{
		printf("%s\n", errmsg);
	}
	else
	{
		printf("Query record done.\n");
	}

	// 所有的记录查询发送完毕之后,给客户端发出一个结束信息
	msg->data[0] = '\0';

	send(acceptfd, msg, sizeof(MSG_t), 0);

	return 0;
}


 效果

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

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

相关文章

项目实战:组件扫描实现(1)-扫描类路径所有文件

1、ComponentScan 组件扫描类 一下知识本人都是在Maven工程下总结的&#xff0c;所以目录结构会不一样这个类的作用是扫描所有的classes目录下的所有的字节码文件&#xff0c;找到相应的类&#xff0c;然后找到相应类上的注解 package com.csdn.mymvc.core; import java.io.Fi…

Single-cell 10x Cell Ranger analysis

first step download SRR data #这是批量下载 nohup prefetch -X 100GB --option-file SRR_Acc_List.txt & nohup fastq-dump --gzip --split-files -A ./SRR13633760 -O /home/scRNA/ &next Build a custom reference using Cell Ranger mkref 首先&#xff0c;找…

音视频技术开发周刊 | 318

每周一期&#xff0c;纵览音视频技术领域的干货。 新闻投稿&#xff1a;contributelivevideostack.com。 日程揭晓&#xff01;速览深圳站大会专题议程详解 LiveVideoStackCon 2023 音视频技术大会深圳站&#xff0c;保持着往届强大的讲师阵容以及高水准的演讲质量。两天的参会…

selenium自动化测试入门 —— 层级定位与定位一组元素

一、层级定位(二次定位) 在实际测试过程中&#xff0c;一个页面可能有多个属性基本相同的元素&#xff0c;如果要定位到其中的一个&#xff0c;这时候需要用到层级定位。先定位其父元素&#xff0c;然后再通过父元素定位该元素。 示例&#xff1a;通过层级定位搜狗输入框 dr…

Mac版eclipse如何安装,运行bpmn文件

一、下载程序包 网址&#xff1a;https://www.eclipse.org/downloads M2芯片安装包名称&#xff1a;eclipse-jee-2022-12-R-macosx-cocoa-aarch64.dmg 具体安装包版本根据自己电脑型号选择 二、eclipse安装步骤 1&#xff09;双击下载的文件 2&#xff09;将eclipse拖入到…

京东大数据:2023年Q3美妆行业数据分析报告

近日&#xff0c;珀莱雅发布三季报&#xff0c;今年前三季度&#xff0c;公司实现营收52.49亿元&#xff0c;同比增长32.47%。分季度看&#xff0c;“618大促”所在Q2业绩增长最为亮眼&#xff0c;营收同比增速达到46.22%&#xff0c;进入Q3&#xff0c;在电商大促缺席情况下&a…

Python---字符串的修改方法---split()方法--切割

split()方法 split 英 /splɪt/ v. 分裂&#xff0c;使分裂&#xff08;成不同的派别&#xff09;&#xff1b;分开&#xff0c;使分开&#xff08;成为几个部份&#xff09;&#xff1b;&#xff08;使&#xff09;撕裂&#xff1b;分担&#xff0c;分享&#xff1b;划破…

Linux:进程控制的概念和理解

文章目录 进程的创建fork函数写时拷贝的原理fork函数的用法和失败原因 进程终止进程的退出进程异常的问题 进程终止进程退出 进程等待什么是进程等待&#xff1f;为什么要进行进程等待&#xff1f;如何进行进程等待&#xff1f;父进程如何知道子进程的退出信息&#xff1f; wai…

element的表单校验证件号规则以及输入“无”的情况校验通过

element的表单校验证件号规则以及输入“无”的情况校验通过 <el-col :span"6"><el-form-item label"证件号码" prop"Idnumber" class"grid-content bg-purple"><el-input v-model"testForm.Idnumber" placeh…

Spark Core

Spark Core 本文来自 B站 黑马程序员 - Spark教程 &#xff1a;原地址 第一章 RDD详解 1.1 为什么需要RDD 分布式计算需要 分区控制shuffle控制数据存储、序列化、发送数据计算API等一系列功能 这些功能&#xff0c;不能简单的通过Python内置的本地集合对象&#xff08;如…

如何使用VSCode来查看二进制文件

2023年11月6日&#xff0c;周一下午 目录 方法1&#xff1a;安装插件Binary Viewer然后用vscode打开一个二进制文件&#xff0c;并点击右上角的"HEX"方法2&#xff1a;安装插件Binary然后用vscode打开一个二进制文件&#xff0c;并点击右上角的"B" 方法1&…

如何使用群晖NAS的Audio Station结合内网穿透实现远程访问本地曲库

文章目录 本教程解决的问题是&#xff1a;按照本教程方法操作后&#xff0c;达到的效果是本教程使用环境&#xff1a;1 群晖系统安装audiostation套件2 下载移动端app3 内网穿透&#xff0c;映射至公网 很多老铁想在上班路上听点喜欢的歌或者相声解解闷儿&#xff0c;于是打开手…

Webpack 中 loader 的作用是什么?常用 loader 有哪些?

说说webpack中常见的Loader&#xff1f;解决了什么问题&#xff1f;- 题目详情 - 前端面试题宝典 1、loader 是什么 loader是 webpack 最重要的部分之一。 通过使用不同的 loader&#xff0c;我们能够调用外部的脚本或者工具&#xff0c;实现对不同格式文件的处理。 loader…

汽车电子中的深力科推荐一款汽车用功率MOSFET NVTFS6H888NLTAG N沟道

NVTFS6H888NLTAG MOSFET是符合AEC-Q101标准的汽车用功率MOSFET&#xff0c;采用WDFN-8封装&#xff0c;实现紧凑设计。具有低QG和电容&#xff08;最大限度地降低驱动器损耗&#xff09;和低 RDS(on)&#xff08;降低传导损耗&#xff09;。还提供可湿性侧翼选项&#xff0c;用…

OpenSign 开源 PDF 电子签名解决方案

OpenSign 是一个开源文档电子签名解决方案&#xff0c;旨在为 DocuSign、PandaDoc、SignNow、Adobe Sign、Smartwaiver、SignRequest、HelloSign 和 Zoho Sign 等商业平台提供安全、可靠且免费的替代方案。 特性&#xff1a; 安全签名&#xff1a;利用最先进的加密算法来确保…

Python 使用Scapy构造特殊数据包

Scapy是一款Python库&#xff0c;可用于构建、发送、接收和解析网络数据包。除了实现端口扫描外&#xff0c;它还可以用于实现各种网络安全工具&#xff0c;例如SynFlood攻击&#xff0c;Sockstress攻击&#xff0c;DNS查询攻击&#xff0c;ARP攻击&#xff0c;ARP中间人等。这…

Akshare获取同花顺行业

使用akshare可以很方便的获取同花顺行业列表&#xff0c;与每个行业对应的个股信息&#xff0c;流程如下&#xff1a; 使用ak.stock_board_industry_summary_ths()获取行业列表循环行业列表&#xff0c;使用ak.stock_board_industry_cons_ths()获取行业对应的个股信息 官方文…

工厂模式 rust和java的实现

文章目录 工厂模式特点介绍工厂模式包含以下几个核心角色&#xff1a;实现架构java 实现rust实现rust代码仓库 工厂模式 工厂模式&#xff08;Factory Pattern&#xff09;是最常用的设计模式之一。这种类型的设计模式属于创建型模式&#xff0c;它提供了一种创建对象的最佳方…

gitlab数据备份和恢复

gitlab数据备份 sudo gitlab-rake gitlab:backup:create备份文件默认存放在/var/opt/gitlab/backups路径下&#xff0c; 生成1697101003_2023_10_12_12.0.3-ee_gitlab_backup.tar 文件 gitlab数据恢复 sudo gitlab-rake gitlab:backup:restore BACKUP1697101003_2023_10_12_…

[C/C++]数据结构 链表OJ题: 链表分割

题目描述: 现有一链表的头指针 ListNode* pHead&#xff0c;给一定值x&#xff0c;编写一段代码将所有小于x的结点排在其余结点之前&#xff0c;且不能改变原来的数据顺序&#xff0c;返回重新排列后的链表的头指针。 解题思路: 创建两个新链表,head1,head2, 遍历原链表,把小于…