UDP英译汉网络词典

这里我们用UDP实现一个简单的英译汉小词典。我们还是仿照前一篇的UDP编程,将各自的组件封装起来,实现高内聚低耦合。

一. 字典翻译功能实现

首先我们将我们的字典知识库放在txt文本中。

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

然后我们来实现翻译功能。为了体现高内聚低耦合的思想,我们仍然封装成一个类。

const string defaultpath="./Dict.txt";class Dict
{
public:Dict(const string& path=defaultpath):_dict_conf_filepath(path){}~Dict(){}
private:unordered_map<string,string> _dict;string _dict_conf_filepath;
}; 

可以看到,类成员有两个,一个是Map类型的,对应我们先前txt文本中的一些汉英对照单词;另一个是string类型的,表明我们应该去哪里找汉英对照。

初始化时我们应该根据txt文本中的中英单词,填充_dict成员。

创建函数:

const string sep=": ";
bool Load()
{ifstream in(_dict_conf_filepath);if(!in.is_open()){LOG(FATAL,"open %s error\n",_dict_conf_filepath);return false;}string line;while(getline(in,line)){if(line.empty()) continue;auto pos=line.find(sep);//[)if(pos==string::npos) continue;string word=line.substr(0,pos);if(word.empty()) continue;string han=line.substr(pos+sep.size());if(han.empty()) continue;LOG(DEBUG,"load info, %s: %s\n",word,han);_dict.insert(make_pair(word,han));}in.close();LOG(DEBUG,"load %s success\n",_dict_conf_filepath.c_str());return true;
}

那么当我们上层调用函数寻找时,就可以根据_dict成员中找结果。

string Translate(const string& word,bool &ok)
{ok=true;auto iter=_dict.find(word);if(iter==_dict.end()){ok=false;return "未找到";}return iter->second;
}

最后我们加上命名空间,由此我们翻译功能实现代码整体如下:

#pragma once#include<iostream>
#include<unordered_map>
#include<fstream>
#include<string>
#include"Log.hpp"using namespace std;namespace dict_ns
{const string defaultpath="./Dict.txt";const string sep=": ";class Dict{private:bool Load(){ifstream in(_dict_conf_filepath);if(!in.is_open()){LOG(FATAL,"open %s error\n",_dict_conf_filepath);return false;}string line;while(getline(in,line)){if(line.empty()) continue;auto pos=line.find(sep);//[)if(pos==string::npos) continue;string word=line.substr(0,pos);if(word.empty()) continue;string han=line.substr(pos+sep.size());if(han.empty()) continue;LOG(DEBUG,"load info, %s: %s\n",word,han);_dict.insert(make_pair(word,han));}in.close();LOG(DEBUG,"load %s success\n",_dict_conf_filepath.c_str());return true;}public:Dict(const string& path=defaultpath):_dict_conf_filepath(path){Load();}string Translate(const string& word,bool &ok){ok=true;auto iter=_dict.find(word);if(iter==_dict.end()){ok=false;return "未找到";}return iter->second;}~Dict(){}private:unordered_map<string,string> _dict;string _dict_conf_filepath;}; 
}

二. 服务端代码实现

我们将服务端封装成一个类,并封装对应步骤在类函数中。

const static int defaultfd = -1;
using func_t=function<string(const string&,bool& ok)>;class UdpServer
{
public:UdpServer(uint16_t port,func_t func): _sockfd(defaultfd), _port(port), _func(func),_isrunning(false){}~UdpServer(){}private:int _sockfd;uint16_t _port; // 服务器所用的端口号bool _isrunning;//给服务器设定回调,用来让上层进行注册业务的处理方法func_t _func;
};

此处有一个自定义类型func_t的变量,我们观察其参数结构,可以发现其实就是我们上面实现的翻译功能类中的Translate函数。我们通过这样的方式,实现高内聚低耦合,让上层实现翻译功能。

此处服务端同样不需要IP地址,与前面原因相同(不知道的同鞋可以看links)。

服务端初始成员函数:

void InitServer(){// 1.创建udp socket 套接字...必须要做的_sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (_sockfd < 0){LOG(FATAL, "socket error,%s,%d\n", strerror(errno), errno);exit(SOCKET_ERROR);}LOG(INFO, "socket create success,sockfd: %d\n", _sockfd);// 2.1 填充sockaddr_in结构struct sockaddr_in local;     // struct sockaddr_in 系统提供的数据类型,local是变量,用户栈上开辟空间bzero(&local, sizeof(local)); // 清空local.sin_family = AF_INET;local.sin_port = htons(_port); // port要经过网络传输给对面,即port先到网络,所以要将_port,从主机序列转化为网络序列local.sin_addr.s_addr=INADDR_ANY;//htonl(INADDR_ANY)// 2.2 bind sockfd和网络信息(IP(?)+Port)int n = bind(_sockfd,(struct sockaddr*)&local,sizeof(local));if(n<0){LOG(FATAL, "bind error,%s,%d\n", strerror(errno), errno);exit(BIND_ERROR);}LOG(INFO, "socket bind success\n");}

此处还是跟前面UDP编程一样。

服务端启动成员函数:

void Start()//所有的服务器,本质解决的是输入输出的问题!不想让网络通信模块和业务模块进行强耦合
{//一直运行,直到管理者不想运行了,服务器都是死循环_isrunning=true;while(true){char request[1024];struct sockaddr_in peer;socklen_t len=sizeof(peer);//1.我们要让server先收数据ssize_t n=recvfrom(_sockfd,request,sizeof(request)-1,0,(struct sockaddr*)&peer,&len);if(n>0){request[n]=0;InetAddr addr(peer);LOG(DEBUG,"get message from [%s:%d]: %s\n",addr.Ip().c_str(),addr.Port(),request);bool ok;string response=_func(request,ok);//将请求回调出去,在外部进行处理(void)ok;//2.我们要将server收到的数据,发回给对方sendto(_sockfd,response.c_str(),response.size(),0,(struct sockaddr*)&peer,len);}}_isrunning=false;
}

此处我们大致思路还是先通过recvfrom函数收到来自客户端的数据,然后再将翻译的结果返回给客户端。在这中间,就是我们的翻译函数,在服务端类中即我们的_func成员。

那么服务端代码合起来就是:

#pragma once
#include <iostream>
#include <string>
#include <cerrno>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <strings.h>
#include <stdlib.h>
#include<functional>
#include "Log.hpp"
#include"InetAddr.hpp"
#include"Dict.hpp"using namespace std;enum
{SOCKET_ERROR = 1,BIND_ERROR,USAGE_ERROR
};const static int defaultfd = -1;
using func_t=function<string(const string&,bool& ok)>;class UdpServer
{
public:UdpServer(uint16_t port,func_t func): _sockfd(defaultfd), _port(port), _func(func),_isrunning(false){}void InitServer(){// 1.创建udp socket 套接字...必须要做的_sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (_sockfd < 0){LOG(FATAL, "socket error,%s,%d\n", strerror(errno), errno);exit(SOCKET_ERROR);}LOG(INFO, "socket create success,sockfd: %d\n", _sockfd);// 2.1 填充sockaddr_in结构struct sockaddr_in local;     // struct sockaddr_in 系统提供的数据类型,local是变量,用户栈上开辟空间bzero(&local, sizeof(local)); // 清空local.sin_family = AF_INET;local.sin_port = htons(_port); // port要经过网络传输给对面,即port先到网络,所以要将_port,从主机序列转化为网络序列local.sin_addr.s_addr=INADDR_ANY;//htonl(INADDR_ANY)// 2.2 bind sockfd和网络信息(IP(?)+Port)int n = bind(_sockfd,(struct sockaddr*)&local,sizeof(local));if(n<0){LOG(FATAL, "bind error,%s,%d\n", strerror(errno), errno);exit(BIND_ERROR);}LOG(INFO, "socket bind success\n");}void Start()//所有的服务器,本质解决的是输入输出的问题!不想让网络通信模块和业务模块进行强耦合{//一直运行,直到管理者不想运行了,服务器都是死循环_isrunning=true;while(true){char request[1024];struct sockaddr_in peer;socklen_t len=sizeof(peer);//1.我们要让server先收数据ssize_t n=recvfrom(_sockfd,request,sizeof(request)-1,0,(struct sockaddr*)&peer,&len);if(n>0){request[n]=0;InetAddr addr(peer);LOG(DEBUG,"get message from [%s:%d]: %s\n",addr.Ip().c_str(),addr.Port(),request);bool ok;string response=_func(request,ok);//将请求回调出去,在外部进行处理(void)ok;//2.我们要将server收到的数据,发回给对方sendto(_sockfd,response.c_str(),response.size(),0,(struct sockaddr*)&peer,len);}}_isrunning=false;}~UdpServer(){}private:int _sockfd;uint16_t _port; // 服务器所用的端口号bool _isrunning;//给服务器设定回调,用来让上层进行注册业务的处理方法func_t _func;
};

三. 服务端调用实现

此处还是跟UDP编程一样,因为我们实际只在服务端代码内部作了改动,在外层看起来调用都是没变的。

#include<iostream>
#include<memory>
#include"UdpServer.hpp"
#include"Log.hpp"
#include"Dict.hpp"
using namespace std;
using namespace dict_ns;void Usage(string proc)
{cout<<"Usage:\n\t"<<proc<<" local_port\n"<<endl;
}// ./udpserver ip
int main(int argc,char *argv[])
{if(argc!=2){Usage(argv[0]);exit(USAGE_ERROR);}EnableScreen();//string ip=argv[1];//定义翻译模块Dict dict;//网络模块uint16_t port=stoi(argv[1]);unique_ptr<UdpServer> usvr=make_unique<UdpServer>(port,\bind(&Dict::Translate,&dict,placeholders::_1,placeholders::_2));//C++14usvr->InitServer();usvr->Start();return 0;
}

四. 客户端代码实现

此处也是没有变化的,所以我们可以体会到我们这种将不同功能的代码分别封装起来思想的好处。可以看到此处跟UDP编程其实变化不大。

#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>using namespace std;void Usage(string proc)
{cout<<"Usage:\n\t"<<proc<<" serverip serverport\n"<<endl;
}// ./udpclient serverip serverport
int main(int argc,char *argv[])
{if(argc!=3){Usage(argv[0]);exit(1);}string serverip=argv[1];uint16_t serverport=stoi(argv[2]);//1.创建socketint sockfd=socket(AF_INET,SOCK_DGRAM,0);if(sockfd<0){cerr<<"socket error"<<endl;}//2.client一定要bind,client也有自己的ip和port,但是不建议显示(和server一样用bind函数)bind//a.那如何bind呢?当udp client首次发送数据的时候,os会自动随机的给client进行bind--为什么?要bind,必然要和port关联!防止client port冲突//b.什么时候bind?首次发送数据的时候//构建目标主机的socket信息struct sockaddr_in server;memset(&server,0,sizeof(server));server.sin_family=AF_INET;server.sin_port=htons(serverport);server.sin_addr.s_addr=inet_addr(serverip.c_str());string message;//3.直接通信即可while(true){cout<<"Please Enter# ";getline(cin,message);sendto(sockfd,message.c_str(),message.size(),0,(struct sockaddr*)&server,sizeof(server));struct sockaddr_in peer;socklen_t len=sizeof(peer);char buffer[1024];ssize_t n=recvfrom(sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);if(n>0){buffer[n]=0;cout<<"server echo# "<<buffer<<endl;}}return 0;
}

五. 效果展示

在这里插入图片描述
此处打印出来的英汉对照有点格式问题,所以没有显示出来,但是我们可以发现翻译出来是没有问题的。

总结:

好了,到这里今天的知识就讲完了,大家有错误一点要在评论指出,我怕我一人搁这瞎bb,没人告诉我错误就寄了。

祝大家越来越好,不用关注我(疯狂暗示)

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

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

相关文章

浮毛粘毛器可以彻底去除吗?独家揭秘值得入手浮毛空气净化器

有没有养猫五年以上还是单猫的铲屎官&#xff1f;能不能分享一下怎么才能控制住不养新猫。 从我养第一只猫开始&#xff0c;每次看到别人家的小幼猫&#xff0c;就控制不住的想养。到现在&#xff0c;家里已经有了7只猫&#xff0c;而前段时间楼下那只小三花又差点让我破例。不…

Keil5 Debug模式Watch窗口添加的监控变量被自动清除

Keil5 Debug模式Watch窗口添加的监控变量被自动清除 问题解决记录 问题描述&#xff1a;每次进入Debug模式时&#xff0c;watch窗口里面上一次调试添加的监控变量都会被全部清掉 如图&#xff1a; 退出Debug模式后&#xff0c;重新进入Debug模式&#xff1a; 解决方法&…

INFO:一种基于向量加权平均的高效优化算法【免费获取Matlab代码】

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献5.代码获取 1.背景 2022年&#xff0c;I Ahmadianfar受到基于向量加权平均方法启发&#xff0c;提出了加权平均向量优化算法&#xff08;weIghted meaN oF vectOrs, INFO&#xff09;。 2.算法原理 2.1算法…

在线任务分发系统开发架构分析

在线任务分发系统的架构分析是一个综合性的过程&#xff0c;涉及多个技术层面和功能模块的设计。以下是对在线任务分发系统架构的详细分析&#xff1a; 一、系统概述 在线任务分发系统是一个集任务发布、分配、执行、监控及反馈于一体的综合平台&#xff0c;它通过互联网技术实…

超详细带你学习go高性能web框架----fiber

go-fiber-fast go-fiber 主要定位为一个轻量级、高性能的 Web 框架&#xff0c;但其灵活性使得它可以通过与其他库的集成&#xff0c;构建出强大而多功能的应用程序&#xff0c;满足不同的业务需求,和gin一样轻量级别的路由,但是性能特别是极端性能比gin好一些,都可以通过整合其…

【Gradle】window下安装gradle及idea配置

gradle安装与配置 背景基本概念下载配置环境变量idea配置构建命令配置全局的镜像仓库 背景 最近在看spring源码时&#xff0c;Spring5 以后都是采用 Gradle 来编译&#xff0c;所以构建源码前先安装 Gradle 环境。 基本概念 Gradle是一个基于Apache Ant和Apache Maven概念的…

优化农业项目流程 10款实用管理系统推荐

国内外主流的 10 款农业建设管理系统对比&#xff1a;PingCode、Worktile、建米农业工程项目管理系统、泛普软件的农业项目管理系统、开创云数字农业管理平台、Trimble Ag Software、Agworld、FarmLogs、Granular、Conservis。 在管理复杂的农业建设项目时&#xff0c;选择合适…

LuaJit分析(三)luajit字节码文件格式

Luajit字节码文件格式的完整信息如上图所示&#xff0c;包括文件头Header和原型Proto&#xff0c;一个原型可以对应lua源码中的一个函数或源文件。一、文件头文件标志&#xff1a;占用三个字节&#xff0c;始终是0x1B4C4A&#xff0c;表示这是一个luajit文件版本&#xff1a;占…

时序预测 | 基于VMD-SSA-LSSVM+LSTM多变量时间序列预测模型(Matlab)

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 旧时回忆&#xff0c;独此一家。基于VMD-SSA-LSSVMLSTM多变量时间序列预测模型&#xff08;Matlab&#xff09; ——————组合模型预测结果—————————— 预测绝对平均误差MAE LSTM VMDSSALSSVM 组合模型 …

Java项目:基于SpringBoot+mysql在线拍卖系统(含源码+数据库+答辩PPT+毕业论文)

一、项目简介 本项目是一套基于SSM框架mysql在线拍卖系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、功能齐全、…

基层医疗云HIS系统源码:云计算、大数据等现代信息技术研发

云HIS源码&#xff0c;基层云HIS系统源码&#xff0c;基层医疗云HIS系统 利用云计算、大数据等现代信息技术研发的基层医疗云HIS系统实现了医院信息化从局域网向互联网转型&#xff0c;重新定义医疗卫生信息化建设的理念、构架、功能和运维体系。实现了医院信息化由局域网向互…

分享两个方法分析python打包exe

在Python开发中&#xff0c;常常需要将Python脚本打包成独立的可执行文件&#xff0c;以便在没有Python环境的电脑上运行。你是否曾为此感到困惑&#xff0c;不知道该选择哪种工具来实现这一目标&#xff1f;其实&#xff0c;打包Python脚本并不难&#xff0c;关键在于选择合适…

C++从入门到起飞之——list模拟实现 全方位剖析!

​ ​ ​ &#x1f308;个人主页&#xff1a;秋风起&#xff0c;再归来~&#x1f525;系列专栏&#xff1a;C从入门到起飞 &#x1f516;克心守己&#xff0c;律己则安 目录 ​ ​1、list的整体框架 2、list迭代器 >整体分析 >整体框架 >成员函数 >运…

windows安全软件之火绒杀毒的密码忘记后处理

一、问题描述 某次&#xff0c;想升级系统补丁&#xff0c;但多次尝试后都失败&#xff0c;排查杀毒软件影响过程中&#xff0c;发现火绒杀毒配置了密码保护&#xff0c;但因时间太久&#xff0c;密码已无从考证&#xff0c;那我们应该怎样处理这种情况呢&#xff1f; 二、处…

开发知识付费小程序的秘诀:从设计到上线一步到位

在移动互联网时代&#xff0c;知识付费小程序成为内容创作者和教育者的热门选择。它不仅降低了用户的使用门槛&#xff0c;还具备高效传播的优势。本文将带你一步步了解如何开发一个功能齐全的知识付费小程序&#xff0c;从设计规划到技术实现&#xff0c;最后顺利上线。 一、…

QT接收并解析GPS模块串口数据

目录 一、QT读取串口数据 二、解析数据 目标&#xff1a; 使用QT&#xff0c;读取gps模块的串口数据&#xff0c;并解析其中的经纬高数据&#xff0c;然后进行处理 一、QT读取串口数据 变量定义 QSerialPort *serial; QSerialPortInfo SerialPortInfo; QByteArray lineData…

RKNPU2从入门到实践 --- 【10】RKNPU2零拷贝API实现RKNN模型在RK3588开发板上的部署

目录 一、为什么叫零拷贝API&#xff1f; 二、零拷贝API执行流程&#xff08;代码解读&#xff09; 2.1 前奏工作 2.2 main.cc文件的编写&#xff08;代码的编写&#xff09; 2.2.1 第一步&#xff1a;rknn_init接口创建rknn_context对象、加载RKNN模型 2.2.2 第二步…

C# 传值参数

传值参数 1.值类型 值参数创建变量的副本&#xff1a;当传递值参数时&#xff0c;实际上是创建了原始变量的一个副本&#xff0c;然后将副本传递给方法。对值参数的操作永远不影响变量的值&#xff1a;由于是复制了一份新的副本&#xff0c;所以对副本进行操作不会影响原始变量…

python,json数据格式,pyecharts模块,pycharm中安装pyecharts

json数据格式 JSON是一种轻量级的数据交互格式 可以按照JSON指定的格式去组织和封装数据 JSON本质上是一个带有特定格式的字符串 主要功能&#xff1a; json就是一种在各个编程语言中流通的数据格式&#xff0c;负责不同编程语言中的数据传递和交互. 类似于&#xff1a; 国…

普元Devops-在云主机上拉取harbor的docker镜像并部署

1 前言 本文讲解如何从普元Devops配置构建&#xff0c;从而实现在云主机上拉取Docker镜像&#xff0c;然后运行Docker容器&#xff0c;实现云主机的Docker部署。 2 主要步骤说明 首先&#xff0c;我们有一个Devops服务器&#xff0c;还有一个云主机服务器&#xff0c;还有一个…