UDP英译汉网络词典

news2024/11/15 21:20:36

这里我们用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++14
    usvr->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.创建socket
    int 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.coloradmin.cn/o/2089708.html

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

相关文章

容器访问外网

目录 1 容器访问外网 1.1 容器访问外网的原理 1.2 容器与外网通讯原理解剖 2 docker跨主机网络 2.1 实现docker跨主机通讯方式 2.2 macvlan网络方式实现跨主机通信 2.2.1 macvlan网络方式 2.2.2 macvlan网络间的隔离和连通 2.2.3 实现方法如下&#xff1a; 1 容器访问外网 1.…

Django+Vue社区养老管理系统的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 需要的环境3.2 Django接口层3.3 实体类3.4 config.ini3.5 启动类3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍&#xff1a;CSDN认证博客专家&#xff0c;CSDN平台Java领域优质创作者&…

详解Spring AOP

前言&#x1f440;~ 上一章我们介绍了SpringBoot统一功能相关的知识点&#xff0c;今天来讲解Spring框架另外一个核心AOP&#xff0c;细&#xff01;&#xff01;&#xff01; 什么是AOP&#xff1f; 什么是面向切面编程呢&#xff1f; 什么是面向特定方法编程呢&#xff1…

Bahdanau注意力机制

介绍 在Bahadanu注意力机制中&#xff0c;本质上是序列到序列学习的注意力机制实现&#xff0c;在编码器-解码器结构中&#xff0c;解码器的每一步解码过程都依赖着整个上下文变量&#xff0c;通过Bahdanau注意力&#xff0c;使得解码器在每一步解码时&#xff0c;对于整个上下…

ET6框架(七)Excel配置工具

文章目录 一、Excel表的基本规则&#xff1a;二、特殊特殊标记三、编译路径说明四、动态获取数据五、可导表类型查看: 一、Excel表的基本规则&#xff1a; 在框架中我们的Excel配置表在ET > Excel文件夹中 1.在表结构中需要注意的是起始点必须在第三行第三列&#xff0c;且…

91.游戏的启动与多开-游戏启动

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a;易道云信息技术研究院 上一个内容&#xff1a;90.游戏安全项目-项目搭建与解析 以90.游戏安全项目-项目搭建与解析它的代码为基础进行…

[java][代码] java中date格式化输出时间字符串

Date date new Date();//具备默认的风格//DateFormat dateFormDateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG);DateFormat dateFormnew SimpleDateFormat("yyyy-mm-dd");System.out.println(dateForm.format(date)); 这段Java代码演示了如何使用S…

YOLOv9改进策略【模型轻量化】| PP-LCnet

一、本文介绍 本文记录的是利用PP-LCNet中的DepSepConv模块优化YOLOv9中的RepNCSPELAN4。YOLOv9在使用辅助分支后&#xff0c;模型的参数量和计算量相对较大&#xff0c;本文利用DepSepConv模块改善模型结构&#xff0c;使模型在几乎不增加延迟的情况下提升网络准确度。 文章目…

海外新闻稿发布对区块链项目具有深远的影响

在知名媒体平台上发布新闻稿对区块链项目具有深远的影响&#xff0c;例如全球雅虎&#xff0c;彭博社这些全球知名财经媒体&#xff0c;能够显著提升项目的曝光度和信誉&#xff0c;吸引潜在投资者以及其他利益相关者的关注。以下是几个方面的详细分析&#xff1a; 1. 增强品牌…

区块链通证系统功能分析

区块链通证系统功能分析涉及多个关键方面&#xff0c;以确保系统能够满足不同的业务需求和合规性要求。 同质与非同质通证&#xff1a;区块链通证系统需要支持同质通证&#xff08;如ERC-20&#xff09;和非同质通证&#xff08;如ERC-721&#xff09;&#xff0c;以适应不同类…

如何快速掌握销售数据?一张报表就够了

在销售管理中&#xff0c;数据是企业做出战略决策的重要依据。有效的销售数据分析不仅能帮助企业精准把握市场动向&#xff0c;还能提高销售团队的工作效率&#xff0c;优化客户关系管理。然而&#xff0c;面对海量的销售数据&#xff0c;如何高效地解读这些数据呢&#xff1f;…

Java SpringBoot实现大学生平时成绩量化管理系统:一步步教你构建高效成绩统计,集成MySQL数据库,打造自动化评分流程

&#x1f34a;作者&#xff1a;计算机毕设匠心工作室 &#x1f34a;简介&#xff1a;毕业后就一直专业从事计算机软件程序开发&#xff0c;至今也有8年工作经验。擅长Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等。 擅长&#xff1a;按照需求定制化开发项目…

three.js 编辑器,动画,着色器, cesium 热力图,聚合点位,大量点线面, 图层,主题,文字,等众多案例中心

对于大多数的开发者来言&#xff0c;看了很多文档可能遇见不到什么有用的&#xff0c;就算有用从文档上看&#xff0c;把代码复制到自己的本地大多数也是不能用的&#xff0c;非常浪费时间和学习成本&#xff0c; 尤其是three.js &#xff0c; cesium.js 这种难度较高&#xff…

ThinkPHP之入门讲解

文章目录 1 ThinkPHP1.1 框架1.1.1 目录讲解1.1.1.1 5.x1.1.1.2 6.0以上 1.1.2 配置文件1.1.2.1 5.x1.1.2.2 6.0以上 1.1.3 函数文件1.1.3.1 5.x1.1.3.1 6.0以上 1.2 控制器1.2.1 控制器的后缀1.2.2 框架中的命名空间1.2.3 url访问1.2.4 调试模式1.2.4.1 5.x1.2.4.2 6.0以上 1.…

Oracle迁移至openGauss的工具:ora2op的安装配置

目录 前言 1. ora2op的下载 1.1 下载地址 1.2 ora2op 介绍 2. ora2op的安装 2.1 安装perl的依赖包 2.2 安装连接Oracle数据库的模块 2.3 安装ora2op 2.4 安装连接openGauss数据库的模块 前言 本工具是使用perl&#xff0c;在安装时会遇到各种问题&#xff0c;解决方式…

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

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

用户体验设计案例:提升电商网站的用户体验

在数字化时代&#xff0c;用户体验设计&#xff08;UX Design&#xff09;已成为影响品牌成功的关键因素之一。尤其是在竞争激烈的电商行业&#xff0c;如何通过优质的用户体验来吸引和留住客户&#xff0c;是每个企业都需要面对的挑战。本文将通过一个具体的电商网站设计案例&…

解析 uni-app 小程序分包策略:合理优化包体积分布

引言 微信小程序的流行使得越来越多的开发者投入到小程序的开发中。但是&#xff0c;随着项目规模的增大&#xff0c;小程序的性能也会面临一些挑战。其中&#xff0c;小程序分包策略是提升性能的重要一环。 同时&#xff0c;uni-app 的流行也使众多的移动端开发者选择使用 u…

AcWing895. 最长上升子序列

这个代码不知道怎么说&#xff0c;反正就是对着代码手算一次就懂了&#xff0c;无需多言&#xff0c;就是俩for循环里面的第二层for的循环条件是j<i,j是从下标1往下标i-1遍历的&#xff0c;每次a【j】<a【i】就在答案数组f【i】上面做出更新。基本的输入样例已经可以覆盖…

揭秘数字水印技术:使用PyQt5实现图像中的LSB隐写术

在当今的数字化世界中&#xff0c;保护信息的安全性和隐秘性变得尤为重要。无论是在保护版权的数字水印&#xff0c;还是在隐秘传输信息的过程中&#xff0c;数字隐写术&#xff08;Steganography&#xff09;都是一种不可或缺的技术。今天&#xff0c;我们将带领大家探索一种简…