Linux与UDP应用1:翻译软件

UDP应用1:翻译软件

本篇介绍

本篇基于UDP编程接口基本使用中封装的服务器和客户端进行改写,基本功能如下:

  1. 从配置文件dict.txt读取到所有的单词和意思
  2. 客户端向服务端发送英文
  3. 服务端向客户端发送英文对应的中文意思

配置文件内容

下面的内容是本次实现使用的配置文件

apple: 苹果
banana: 香蕉
cat: 猫
dog: 狗
book: 书
pen: 笔
happy: 快乐的
sad: 悲伤的
run: 跑
jump: 跳
teacher: 老师
student: 学生
car: 汽车
bus: 公交车
love: 爱
hate: 恨
hello: 你好
goodbye: 再见
summer: 夏天
winter: 冬天

设计翻译软件

根据上面对功能描述,下面对功能实现进行具体分析

设计字典类

既然是字典类,那么对应的就需要一个便于查询的结构,本次以哈希表为例

因为服务端主要是接收客户端的数据,所以服务端本身不直接处理翻译功能,而是交给一个函数进行处理,但是如果这个函数直接裸露在外部就会导致字典本身和翻译函数分开,所以本次考虑将翻译函数作为字典类的成员函数

需要注意,本次默认使用的配置文件中英文单词和中文意思使用的是一个冒号和空格进行分割,即: ,可以考虑让用户自己提供配置文件和分割符,所以类基本结构如下:

// 默认配置文件位置和配置文件
const std::string default_path = "./";
const std::string default_file = "dict.txt";// 默认分隔符
const std::string default_sep = ": ";class Dictionary
{
public:Dictionary(const std::string &path = default_path, const std::string &file = default_file, const std::string &sep = default_sep): _path(path), _file(file), _sep(sep){// 1. 读取配置文件// 2. 分割字符串并将key和value添加到哈希表}// 翻译std::string translate(const std::string &word){}~Dictionary(){}private:std::unordered_map<std::string, std::string> _dict; // 字典哈希表std::string _path;                                  // 配置文件路径std::string _file;                                  // 配置文件std::string _sep;                                   // 分隔符
};

读取配置文件并分割

首先是读取配置文件,本次考虑将从配置文件中读取到的字符串通过分割成keyvalue依次存入到一个哈希表中。并且因为是字典类,所以考虑在创建字典类对象时就完成前面的读取和存储操作

根据上面的思路需要考虑两个步骤:

  1. 获取并读取配置文件
  2. 分割字符串获取到keyvalue存储到哈希表

读取配置文件的操作就是打开指定的文件并读取其中的内容,在本次配置文件的内容中,一行为一组数据,所以在读取文件内容时需要按照行读取

读到一行数据后,需要将该行数据按照指定的分隔符进行切割存入keyvalue中,这里有两种思路:

  1. 自行实现分割逻辑
  2. 使用库函数

本次考虑使用第一种思路,那么对于分割逻辑来说,基本思路如下:

  1. 找到:第一次出现的位置,以该位置为终点,以字符串第一个字符为起点,切出第一个子串作为key
  2. 找到分隔符的下一个字符,以该位置为起点,以字符串结尾为终点,切出第二个子串作为value

将获取到的keyvalue存入到哈希表中

重复上面的步骤直到读取完毕文件,将文件关闭,代码如下:

// 1. 读取配置文件
std::string dictPath = default_path + default_file;
// 1.1 打开文件
std::fstream out(dictPath);// 2. 分割字符串并将key和value添加到哈希表
std::string message;
while (std::getline(out, message))
{// 分割字符串auto word_end = message.find(_sep, 0);std::string key = message.substr(0, word_end);std::string value = message.substr(word_end + sep.size(), message.size());// 存储到哈希表中_dict.insert({key, value});
}out.close();

翻译函数

所谓翻译就是在哈希表中根据指定字符串查找对应的value并返回,基本代码如下:

// 翻译
std::string translate(const std::string &word)
{auto pos = _dict.find(word);if (pos == _dict.end())return "无指定单词对应的中文意思";return pos->second;
}

修改服务端类

本次服务端做的任务就是接收客户端发送的数据,再调用字典类的翻译函数将翻译结果返回给客户端,所以实际上需要修改的就是两点:

  1. 服务端需要拿到翻译函数
  2. 执行翻译功能并返回结果给客户端

首先修改第一点,因为服务端本身没有翻译函数,所以需要外界传递,此时可以考虑在构造服务端时要求外部传递翻译函数,对应地服务端就需要一个成员用于接收这个函数:

using task_t = std::function<std::string(const std::string &)>;class UdpServer
{
public:UdpServer(task_t t, uint16_t port = default_port): // ...,_translate(t){// ...}// ...
private:// ...task_t _translate; // 翻译函数
};

需要注意,在构造函数中,没有默认参数的形式参数一定要写在有默认参数的形式参数之前,具体原因见C++中的缺省参数
接着修改第二点,执行翻译函数并将结果返回给客户端,这一步主要涉及到服务端的任务部分。在上一节中,主要任务是将客户端发送的信息再发给客户端,这次就是调用翻译函数再将结果返回给客户端,所以代码如下:

// 启动服务器
void start()
{if (!_isRunning){_isRunning = true;while (true){// 1. 接收客户端信息// ...if (ret > 0){// ...// 翻译std::string ret = _translate(buffer);ssize_t n = sendto(_socketfd, ret.c_str(), ret.size(), 0, &temp, temp.getLength());// ...}}}
}

修改服务端主函数

主要修改的地方就是创建服务端对象部分,因为需要传递一个翻译任务函数,所以需要先创建一个字典类对象,再调用字典类对象中的翻译方法,需要注意的是,不能直接将字典类的翻译函数作为参数传递给服务端对象的构造函数,因为该函数的参数列表除了需要显示传递的字符串对象外,还存在一个字典类对象,这并不符合服务端类构造函数要求的函数类型,这里提供两个方法:

  1. 使用绑定,将字典类对象作为固定参数绑定给翻译函数
  2. 使用lambda表达式,在表达式中调用翻译函数

即:

=== “绑定”

// 创建字典类对象
std::shared_ptr<Dictionary> dict;
// 创建UdpServerModule对象
std::shared_ptr<UdpServer> udp_server = = std::make_shared<UdpServer>(std::bind(&Dictionary::translate, dict.get(), std::placeholders::_1));

=== “lambda表达式”

// 创建字典类对象
std::shared_ptr<Dictionary> dict;
// 创建UdpServerModule对象
std::shared_ptr<UdpServer> udp_server = = std::make_shared<UdpServer>([&dict](const std::string word){ dict->translate(word); 
});

测试

以绑定为例,服务端整体代码如下:

#include "udp_server.hpp"
#include "dictionary.hpp"
#include <memory>using namespace UdpServerModule;
using namespace DictionaryModule;int main(int argc, char *argv[])
{// 创建字典类对象std::shared_ptr<Dictionary> dict;// 创建UdpServerModule对象std::shared_ptr<UdpServer> udp_server;if (argc == 1){// 绑定udp_server = std::make_shared<UdpServer>(std::bind(&Dictionary::translate, dict.get(), std::placeholders::_1));}else if (argc == 2){// std::string ip = argv[1]; 去除uint16_t port = std::stoi(argv[1]);udp_server = std::make_shared<UdpServer>(std::bind(&Dictionary::translate, dict.get(), std::placeholders::_1), port);}else{LOG(LogLevel::ERROR) << "错误使用,正确使用:" << argv[0] << " 端口(或者不写)";exit(4);}udp_server->start();return 0;
}

客户端代码保持和上一节一样,此处不再展示,运行结果如下:
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【机器学习】逻辑回归(Logistic Regression)

逻辑回归 逻辑回归逻辑回归的流程Sigmoid函数Sigmoid函数的公式及图像 逻辑回归的损失函数与最优化求解逻辑回归使用梯度下降法求解 逻辑回归 逻辑回归与线性回归都是线性模型&#xff0c;其中线性回归使用线性式来预测数值&#xff0c;逻辑回归使用线性式来进行分类任务。 逻…

IDEA - 查看类的继承结构(通过快捷键查看、通过生成类图查看)

一、通过快捷键查看 在项目中定位到目标类&#xff08;例如&#xff0c;Executor.java&#xff09; 按下快捷键 【Ctrl H】 此时会弹出 Type Hierarchy 窗口&#xff0c;展示所有相关的父类、子类、接口 二、通过生成类图查看 在项目中定位到目标类&#xff08;例如&#x…

Leetcode-1776. Car Fleet II [C++][Java]

目录 一、题目描述 二、解题思路 【C】 【Java】 Leetcode-1776. Car Fleet IIhttps://leetcode.com/problems/car-fleet-ii/description/ 一、题目描述 There are n cars traveling at different speeds in the same direction along a one-lane road. You are given an …

《Python实战进阶》No 9:使用 Celery 实现异步任务队列

第9集&#xff1a;使用 Celery 实现异步任务队列 引言 在现代 Web 应用中&#xff0c;许多操作&#xff08;如发送邮件、处理文件上传、执行复杂计算等&#xff09;可能需要耗费较长时间。如果这些操作直接在主线程中执行&#xff0c;会导致用户请求阻塞&#xff0c;降低用户体…

ue5 创建多列StreeView的方法与理解

创建StreeView的多列样式怎么就像是创建单行单列差不多?貌似就是在单行单列中加入了多列widget? 目录结构: 必备条件 StreeView的多列创建需要的必备条件: 数据基类 CustomItemBase #pragma once /* ---------------------------------- | Name | Value …

Spring的下载与配置

1. 下载spring开发包 下载地址&#xff1a;https://repo.spring.io/webapp/#/artifacts/browse/simple/General/libs-release-local/org/springframework/spring 打开之后可以看到有很多版本供选择&#xff0c;因为视频教程用的是4.2.4版本&#xff0c;于是我也选择这个 右键…

Python + requests实现接口自动化框架

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 为什么要做接口自动化框架 1、业务与配置的分离 2、数据与程序的分离&#xff1b;数据的变更不影响程序 3、有日志功能&#xff0c;实现无人值守 4、自动发送测…

Linux——基本指令

我们今天学习Linux最基础的指令 ls 指令 语法&#xff1a; ls [选项] [⽬录或⽂件] 功能&#xff1a;对于⽬录&#xff0c;该命令列出该⽬录下的所有⼦⽬录与⽂件。对于⽂件&#xff0c;将列出⽂件名以及其他信 息。 命令中的选项&#xff0c;一次可以传递多个 &#xff0c…

【Godot4.3】自定义简易菜单栏节点ETDMenuBar

概述 Godot中的菜单创建是一个复杂的灾难性工作&#xff0c;往往无从下手&#xff0c;我也是不止一次尝试简化菜单的创建。 从自己去年的发明“简易树形数据”用于简化Tree控件获得灵感&#xff0c;于是尝试编写了用于表示菜单数据的EasyMenuData类&#xff0c;以及对应的纯文…

esp32串口通信

1、查看esp32的引脚图&#xff0c;寻找对应的串口 根据原理图&#xff0c;芯片上有3个串口(UART0, UART1和UART2)&#xff0c;但是UART1没有引出引脚。其中UART0&#xff08;GPIO3用于U0RXD&#xff0c;GPIO1用于U0TXD&#xff09;用作下载、调试串口&#xff0c;引脚不可改变&…

内部静态类和非内部静态类的区别

目录 问题&#xff1a; 原理&#xff1a; 外部类与非内部静态类 外部类与静态内部类 加载顺序 总结&#xff1a; 1.非静态内部类依赖于外部类的实例&#xff0c;而静态内部类不依赖于外部类的实例。 2.非静态内部类可以访问外部类的实例变量和方法&#xff0c;而静态内部…

Redis分布式锁的实现(Redission)

写在前面 本人在学习Redis过程中学习到分布式锁时太多困惑和疑难杂点 需要总结梳理思路 以下思路都是最简单最基本的思路 主要用到Redission工具类 会涉及到看门狗机制等 本文内容部分引自Javaguide,小林coding等热门八股 用于个人学习用途 分布式锁介绍 对于单机多线程来说…

【愚公系列】《Python网络爬虫从入门到精通》038-SQLite数据库

标题详情作者简介愚公搬代码头衔华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,CSDN商业化专家,阿里云专家博主,阿里云签约作者,腾讯云优秀博主,腾讯云内容共创官,掘金优秀博主,亚马逊技领云博主,51CTO博客专家等。近期荣誉2022年度…

【开源免费】基于SpringBoot+Vue.JS网络海鲜市场系统(JAVA毕业设计)

本文项目编号 T 222 &#xff0c;文末自助获取源码 \color{red}{T222&#xff0c;文末自助获取源码} T222&#xff0c;文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…

JDK17安装方法/如何安装JDK17/环境变量配置

双击安装 我们这里安装jdk17 然后更改jdk目录 jdk环境变量配置 右键——>此电脑——>高级系统设置——>环境变量 当前用户的环境变量&#xff0c;另外有一个系统变量。 一般我们配置系统环境变量 一、配置JAVA_HOME 这里我们配置一个JAVA_HOME 我这里先前的jdk…

python集合set的常用方法

目录 集合的定义 集合的基础操作 多个集合之间的操作 集合的for循环 集合的定义 集合的基础操作 集合.add(元素) 添加新元素 集合.pop() 从集合中随机取出一个元素 集合.clear() 清空集合 集合.remove(元素) 移除元素 #定义集合,集合自动去重了 set1{"春"…

看得见摸得着的AI:具身智能

“如果Siri有手有脚&#xff0c;你的生活会变成什么样&#xff1f;” 想象一下&#xff1a; • 你家的扫地机器人不再横冲直撞&#xff0c;而是像猫咪一样轻巧绕过桌脚 • 手机里的语音助手能“摸”到你发烧的额头&#xff0c;主动帮你叫医生 • 工厂里的机械臂会边干活边学习&…

ES、OAS、ERP、电子政务、企业信息化(高软35)

系列文章目录 ES、OAS、ERP、电子政务、企业信息化 文章目录 系列文章目录前言一、专家系统&#xff08;ES&#xff09;二、办公自动化系统&#xff08;OAS&#xff09;三、企业资源规划&#xff08;ERP&#xff09;四、典型信息系统架构模型1.政府信息化和电子政务2.企业信息…

【算法学习之路】4.简单数论(4)

简单数论&#xff08;4&#xff09; 前言三.高精度1.什么是高精度2.解决办法 精度乘除法一.精度乘法1.数据的存储2.步骤3.例题&#xff1a;高精度乘法 二.精度除法1.例子2.步骤3.例题&#xff1a;高精度除法 前言 我会将一些常用的算法以及对应的题单给写完&#xff0c;形成一套…

Linux 动静态库和_make_进度条(一)

文章目录 一、如何理解条件编译二、动静态库1. 理论2. 实践3. 解决普通用户的sudo问题4. 技术上理解库 三、make和make_file 一、如何理解条件编译 1. gcc code.c -o code -DM 命令行级别的宏定义预处理的本质就是修改编辑我们的文本代码 头文件展开到源文件中去注释宏替换条…