【在线词典】项目实现

news2025/1/16 1:43:41

15_Dictionary

在线词典

搭建客户端-服务器架构

准备必要的资源

整理原始数据

整理英汉双语对照表,将XLSX格式转换成CSV格式,准备好vocabulary_list.csv文件备用
注意:CSV格式的文件必须使用UTF-8的字符集;

建立mydatabase.db数据库,并创建dictionary表;

shell命令行终端输入sqlite3 mydatabase.db

create table dictionary (
English text not null,
Chinese text not null);

sqlite3当中CSV格式的导入

.mode csv
.import vocabulary_list.csv dictionary

查询数据

select * from dictionary where English='main';

如果显示如下信息表示配置成功:

main,"a.主要的,最重要的"

在这里插入图片描述

实现服务端代码:

udp.h

包含必要的头文件,定义必要的宏,定义函数指针

#ifndef _UDP_H_
#define _UDP_H_

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

#define ErrExit(msg) printf("[%s:%d]%s:%s", __FUNCTION__, __LINE__,msg, strerror(errno)), exit(EXIT_FAILURE)

#endif

udp.c

实现UDP通信,预留udp_main接口

#include "udp.h"

extern void udp_main(const int fd, const struct sockaddr_in *addr);

int main(int argc, const char *argv[])
{
	/* 1.检查参数 */
	if(argc < 3) {
		printf("[%s][addr][port]\n", argv[0]);
		exit(EXIT_FAILURE);
	}

	/* 2.创建数据报套接字 */
	int fd = socket(AF_INET, SOCK_DGRAM, 0);
	if(fd < 0)
		ErrExit("socket");

	/* 3.设置通信结构体 */
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons( atoi(argv[2]) );
	if( inet_aton(argv[1], &addr.sin_addr) == 0) {
		printf("[%s:%d] Invalid address\n", __FUNCTION__, __LINE__);
		exit(EXIT_FAILURE);
	}

	/* 4.绑定通信结构体 */
	if( bind(fd, (struct sockaddr *)&addr, sizeof(addr) ) )
		ErrExit("bind");

	/* 5.处理客户端数据 */
	udp_main(fd, &addr);
	
	/* 6.关闭套接字 */
	close(fd);
	return 0;
}

udp_main.c

预留的客户端数据处理接口

#include "udp.h"

/* 其他必要的环境已封装好了,只需要实现与客户端的交互即可
 * 这里的fd是服务端的socket,
 * addr是服务端的地址*/
void udp_main(const int fd, const struct sockaddr_in *addr) {
	printf("udp main test.\n");
}

实现词典查询功能

在文件udp_main.c实现词典查询功能

#include "udp.h"
#include <ctype.h>
#include <sqlite3.h>

#define DATABASE_NAME "mydatabase.db"

int callback(void *, int, char **, char **);

/* 其他必要的环境已封装好了,只需要实现与客户端的交互即可
 * 这里的fd是服务端的socket,
 * addr是服务端的地址*/
void udp_main(const int fd, const struct sockaddr_in *addr) {
	int ret = 0, rc;
	struct sockaddr_in client_addr;
	socklen_t addrlen = sizeof(client_addr);
	sqlite3 *db;
	char buf[BUFSIZ] = {};
	char *sql_query, *errmsg;

	/* 1.打开数据库 */
	if( (rc = sqlite3_open(DATABASE_NAME, &db) ) ) {
		printf("[%s:%d]无法打开数据库: %s\n", __FUNCTION__, __LINE__, sqlite3_errmsg(db) );
		exit(0);
	}
	/* 2.循环处理客户端数据 */
	while(1) {
		/* 2.1.接收客户端数据 */
		do {
			ret = recvfrom(fd, buf, BUFSIZ, 0, (struct sockaddr *)&client_addr, &addrlen);
		}while(ret < 0 && errno == EINTR);
		if(ret < 0)
			ErrExit("recvfrom");

		printf("[%s:%d]收到的数据: {%s}\n", __FUNCTION__, __LINE__, buf);
		/* 2.2.提取需要翻译的单词 */
		for(ret = 0; isalpha(buf[ret]) || buf[ret] == ' '; ret++);
		buf[ret] = '\0';
		/* 2.3.用SQL语句进行查询 */
		sql_query = sqlite3_mprintf("select * from dictionary where english like '%s'", buf);
		rc = sqlite3_exec(db, sql_query, callback, buf, &errmsg);
		if(rc != SQLITE_OK) {
			sprintf(buf, "查询失败:%s\n", errmsg);
			printf("[%s:%d]%s", __FUNCTION__, __LINE__, buf);
			sendto(fd, buf, strlen(buf) + 1, 0, (struct sockaddr *)&client_addr, addrlen);
			sqlite3_free(errmsg);
			continue;
		}
		sqlite3_free(sql_query);
		printf("[%s:%d]查询结果: {%s}\n", __FUNCTION__, __LINE__, buf);
		sendto(fd, buf, strlen(buf) + 1, 0, (struct sockaddr *)&client_addr, addrlen);
	}
	sqlite3_close(db);
	/* 3.关闭数据库,关闭fd,并且退出程序 */
	close(fd);
}

int callback(void *NotUsed, int argc, char **argv, char **ColName) {
	char *buf = NotUsed;
	if(argc == 2) {
		/* 把查询到的字符串复制给buf */
		strncpy(buf, argv[1], strlen(argv[1]) + 1 );
	} else
		buf[0] = '\0'; //如果失败就将字符串置空
	/* 将换行符替换为'\0' */
	buf[strlen(argv[1])] = '\n';
	buf[strlen(argv[1])+1] = '\0';
	return 0;
}

实现用户操作和服务端交互过程

接下来我们把文件组织成如下形式(执行tree命令可以看到):
在这里插入图片描述

备注:如果没安装:可以使用sudo apt-get install tree命令进行安装

设置环境变量

编辑.bashrc文件
执行sudo vim ~/.bashrc打开家目录下的.bashrc在文件末尾加上如下两句:

export DICTIONARY_SERVER_HOST='127.0.0.1'
export DICTIONARY_SERVER_PORT='8888'

在这里插入图片描述
然后再执行source ~/.bashrc让.bashrc生效
最后执行env | grep DICTIONARY,如果能看到我们刚设置的命令表示环境变量生效了
在这里插入图片描述

connect函数是否可以用在UDP通信当中?

在UDP通信中,使用connect()函数发出“虚拟连接请求”,以便建立虚拟连接。通过调用connect()函数,可以将UDP套接字绑定到目标IP地址和端口上,从而为UDP数据报提供一个默认的发送目的地。这样,在后续的send()函数调用中,就不需要再指定IP地址和端口。
但是,需要注意的是,在UDP通信中,由于不存在真正的连接,因此connect()函数并不会像TCP中那样进行三次握手。它只是在内核中存储了该套接字的目标地址,并在后续的send()或recv()函数调用中使用该目标地址。
下面是一个示例代码片段,展示如何在UDP通信中使用connect()函数:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/socket.h>

#define BUF_SIZE 1024

int main(int argc, char *argv[]) {
    if (argc != 3) {
        printf("Usage: %s <IP> <port>\n", argv[0]);
        exit(1);
    }

    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1) {
        perror("socket");
        exit(1);
    }

    struct sockaddr_in dest_addr;
    memset(&dest_addr, 0, sizeof(dest_addr));
    dest_addr.sin_family = AF_INET;
    dest_addr.sin_addr.s_addr = inet_addr(argv[1]);
    dest_addr.sin_port = htons(atoi(argv[2]));

    if (connect(sockfd, (struct sockaddr *)&dest_addr, sizeof(dest_addr)) == -1) {
        perror("connect");
        exit(1);
    }

    char buf[BUF_SIZE];
    printf("Enter message: ");
    fgets(buf, BUF_SIZE, stdin);

    if (send(sockfd, buf, strlen(buf), 0) == -1) {
        perror("send");
        exit(1);
    }

    close(sockfd);
    return 0;
}

编写客户端代码

这里我们对client下的文件进行编辑:

udp.c

#include "udp.h"

extern void udp_main(const int fd, const char *argv);

int main(int argc, const char *argv[])
{
	/* 获取环境变量DICTIONARY_SERVER_PORT */
	char *port = getenv("DICTIONARY_SERVER_PORT");
	if(port == NULL) {
		printf("没有发现环境变量[DICTIONARY_SERVER_PORT]\n");
		exit(EXIT_FAILURE);
	}

	/* 获取环境变量DICTIONARY_SERVER_HOST */
	char *host = getenv("DICTIONARY_SERVER_HOST");
	if(port == NULL) {
		printf("没有发现环境变量[DICTIONARY_SERVER_HOST]\n");
		exit(EXIT_FAILURE);
	}

	/* 检查参数, 其中第二个参数是需要翻译的单词 */
	if(argc < 2) {
		printf("[%s][word]\n", argv[0]);
		exit(EXIT_FAILURE);
	}
	
	/* 打印环境变量的值 */
	printf("服务器的主机IP是%s, 端口号是%s\n", host, port);
	int fd = socket(AF_INET, SOCK_DGRAM, 0);
	if(fd < 0)
		ErrExit("socket");

	/* 设置通信结构体 */
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons( atoi(port) );
	if( inet_aton( host, &addr.sin_addr) == 0) {
		printf("[%s:%d] Invalid address\n", __FUNCTION__, __LINE__);
		exit(EXIT_FAILURE);
	}

	/* 发起连接请求,注意UDP连接没有三次握手, 不存在连接失败, 只是确定接受端而已 */
	if(connect(fd, (struct sockaddr *)&addr, sizeof(addr) ) )
		ErrExit("connect");

	/* 执行客户端处理程序 */
	udp_main(fd, argv[1]);
	
	/* 关闭套接字 */
	close(fd);

	return 0;
}

udp_main.c

#include "udp.h"

/* 其他必要的环境已封装好了,只需要实现与客户端的交互即可
 * 这里的fd是服务端的socket,
 * addr是服务端的地址*/
extern void udp_main(const int fd, const char *argv) {
	char buf[BUFSIZ] = {};
	send(fd, argv, strlen(argv) + 1, 0);
	recv(fd, buf, BUFSIZ, 0);
	printf("buf=%s\n", buf);
}

编译

执行gcc *.c -o test -Wall -lsqlite3 -I ../head/, 得到test的可执行文件;
然后分别运行两边的test文件:
在这里插入图片描述

得到类似这样的结果表示,代码没有问题,可以得到想要的结果
至此就实现了基本功能,接下来再实现其它附加的功能

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

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

相关文章

第17周:天气预测

目录 前言 一、前期准备 1.1 导入库 1.2 导入数据 1.2.1 数据介绍 1.2.2 数据导入 二、探索式数据分析&#xff08;EDA&#xff09; 2.1 数据相关性探索 2.2 是否会下雨 2.3 地理位置与下雨的关系 2.4 湿度和压力对下雨的影响 2.5 气温对下雨的影响 三、数据预处理…

Windows 零散记录

文章目录 一、鼠标焦点丢失 一、鼠标焦点丢失 如&#xff1a;打字时没打完鼠标焦点中途就消失了 解决&#xff1a; 1、windowsR 组合键打开运行&#xff0c;输入regedit打开注册表 2、找到目录 HKEY_CURRENT_USER\Control Panel\Desktop\ForegroundLockTimeout 设置锁定超时时…

starRocks搭建

公司要使用新的大数据架构&#xff0c;打算用国产代替国外的大数据平台。所以这里我就纠结用doris还是starrocks&#xff0c;如果用doris&#xff0c;因为是开源的&#xff0c;以后就可以直接用云厂商的。如果用starrocks就得自己搭建&#xff0c;但是以后肯定会商业化&#xf…

ARM功耗管理之多核处理器启动

安全之安全(security)博客目录导读 思考&#xff1a;SecureBoot&#xff1f;多核处理器启动流程&#xff1f;PSCI启动方式&#xff1f; 一般嵌入式系统使用的都是对称多处理器&#xff08;Symmetric Multi-Processor, SMP&#xff09;系统&#xff0c;包含了多个cpu, 这几个cp…

脑电图 (EEG) :语音脑机接口(BCI)的理想选择

运动性语言障碍是一种严重的医疗状况&#xff0c;它让患者几乎或完全失去说话能力。这种状况在帕金森病患者中的发生率为90%&#xff0c;在中风患者中的发生率为45.2%&#xff0c;在肌萎缩侧索硬化症&#xff08;ALS&#xff09;患者中的发生率为95%。典型的针对语言障碍的沟通…

轮转数组(超详细!)

前言&#xff1a; 小编在上一篇文章的时候拿过轮转数组作为例子来讲述复杂度&#xff0c;但是小编并没有给出这个题目的正确解答&#xff0c;既然读者朋友已经了解复杂度了&#xff08;不了解也没关系&#xff0c;可以看小编上一篇文章&#xff09;&#xff0c;下面&#xff0c…

木舟0基础学习Java的第十六天(异常,分类,自定义异常,注意事项)

异常 异常概述&#xff1a;异常是Java程序运行过程中出现的错误 异常分类&#xff1a;API查找Throwable 1.Error(服务器宕机&#xff0c;数据库崩溃等) 2.Exception C(异常的继承体系)API查RuntimeException 运行时异常&#xff1a;一般是程序员的错误异常可以让我们发现错…

LiveNVR监控流媒体Onvif/RTSP用户手册-用户管理:编辑、添加用户、关联通道、重置密码、删除、过滤搜索

LiveNVR监控流媒体Onvif/RTSP用户手册-用户管理:编辑、添加用户、关联通道、重置密码、删除、过滤搜索 1、用户管理1.1、添加用户1.2、关联通道1.3、重置密码1.4、编辑1.5、删除1.6、过滤搜索 2、RTSP/HLS/FLV/RTMP拉流Onvif流媒体服务 1、用户管理 1.1、添加用户 点击用户管理…

【源码开源】C#桌面应用开发:串口调试助手

c#桌面应用开发 1、环境搭建和工程创建&#xff1a;参照番茄定时器项目 工程创建参照 2、界面布局设计 3、具体功能函数 &#xff08;1&#xff09;端口扫描&#xff1a; private void btn_com_scan_Click(object sender, EventArgs e){//端口号扫描ReflashPortToComboBox(…

【JavaWeb程序设计】JavaBean(二)

目录 一、请设计并实现下面的Web应用 1. 运行结果 2. inputNumber.jsp代码 3. ComputerBean.java代码 4. handleCompute 5. lookResult.jsp 二、基于MVC模式完成用户注册功能&#xff0c;不允许添加重名用户&#xff0c;使用AJAX技术在用户填写时进行检查并提示是否重复&…

【产品经理】WMS多仓调拨转移说明

对于仓储管理来说&#xff0c;越来越多企业开始应用WMS进行系统化的管理&#xff0c;以提升仓库的作业效率。本文作者从业务流程和基础功能两个方面展开介绍&#xff0c;希望对你有帮助。 一、业务流程 。在线下业务流程拓展&#xff0c;仓库不断增多的过程中&#xff0c;由于…

[leetcode]circular-array-loop 环形数组是否存在循环

. - 力扣&#xff08;LeetCode&#xff09; class Solution { public:bool circularArrayLoop(vector<int>& nums) {int n nums.size();auto next [&](int cur) {return ((cur nums[cur]) % n n) % n; // 保证返回值在 [0,n) 中};for (int i 0; i < n; i…

Apache AGE 运算符

运算符 字符串特定比较运算符 测试数据 SELECT * FROM cypher(graph_name, $$ CREATE (:Person {name: John}),(:Person {name: Jeff}),(:Person {name: Joan}),(:Person {name: Bill}) $$) AS (result agtype);Starts With 对字符串执行区分大小写的前缀搜索。 SELECT * …

Vue2-集成Element-ui、Fontawesome、Axios介绍与使用

文章目录 前期准备Element UI介绍Element-ui安装使用Fontawesome介绍Fontawesome安装使用Axios介绍Axios安装使用本篇小结 更多相关内容可查看 前期准备 脚手架生成vue2项目&#xff1a;NodeJS安装并生成Vue脚手架(保姆级) Element UI介绍 Element UI 是一个基于 Vue.js 2.0…

【Node.js安装教程】

Node.js安装教程 第一步&#xff1a;下载 下载链接&#xff1a;https://nodejs.org/zh-cn 第二步&#xff1a;安装 **方法一&#xff1a;**建议安装在默认路径 方法二&#xff1a;如果不是默认安装路径可能会出现一系列问题&#xff1a;这时可以选择卸载重装或者配置环境变量…

将vue项目整合到springboot项目中并在阿里云上运行

第一步&#xff0c;使用springboot中的thymeleaf模板引擎 导入依赖 <!-- thymeleaf 模板 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency> 在r…

帕金森老人的锻炼建议

对于帕金森病老人来说&#xff0c;适当的锻炼可以帮助改善症状、增强肌肉力量、提高关节灵活性&#xff0c;并预防长期并发症。以下是一些基于最新信息的锻炼建议&#xff1a; 选择合适的运动类型&#xff1a;包括有氧运动、抗阻运动和牵伸运动。有氧运动如快走、慢跑、游泳和舞…

Python酷库之旅-第三方库Pandas(017)

目录 一、用法精讲 41、pandas.melt函数 41-1、语法 41-2、参数 41-3、功能 41-4、返回值 41-5、说明 41-5-1、宽格式数据(Wide Format) 41-5-2、长格式数据(Long Format) 41-6、用法 41-6-1、数据准备 41-6-2、代码示例 41-6-3、结果输出 42、pandas.pivot函数 …

.net C# 使用网易163邮箱搭建smtp服务,实现发送邮件功能

功能描述&#xff1a;使用邮箱验证实现用户注册激活和找回密码。邮箱选择网易163作为smtp服务器。 真实测试情况&#xff1a;第一种&#xff1a;大部分服务器运行商的25端口默认是封禁的&#xff0c;可以联系运营商进行25端口解封&#xff0c;解封之后可以使用25端口。第二种&…

电力需求预测挑战赛笔记 Taks1 跑通baseline

#AI夏令营 #Datawhale #夏令营 赛题 一句话介绍赛题任务可以这样理解赛题&#xff1a; 【训练时序预测模型助力电力需求预测】 电力需求的准确预测对于电网的稳定运行、能源的有效管理以及可再生能源的整合至关重要。 赛题任务 给定多个房屋对应电力消耗历史 N 天的相关序列数…