在我们每个人都曾经历过“沮丧”时刻里,
如果我们不能对别人说有益的好话,
那我们最好还是什么也别说。
--- 卡耐基 《人性的弱点》---
从零开始使用UDP进行socket编程
1 前情提要
上一篇文章中,我们通过UDP协议实现了客户端和服务端的通信:客户端与服务端通信实现
- 通过socket接口创建socket文件,注意服务端可以主动绑定端口,客户端只可以进行被动绑定!!!
- 通过sendto接口根据目标IP地址以及端口号进行发送数据,发送的数据会讲发送者的IP地址和端口一并发送!
- 通过recvfrom接口从socket文件中进行获取信息,并得到发送者信息!
通过这三个接口我们实现了服务端和客户端之间的通信过程,接下来我们就来添加一些业务逻辑,让我们的客户端与服务端的通信更加实用!!!
下面我们将进行两个小项目:
- 模拟实现单词翻译交互
- 模拟实现多人聊天室
2 单词翻译
2.1 业务需求
我们需要实现的是:
- 服务端根据配置文件形成字典数据结构,可以通过单词快速检索汉语翻译
- 客户端可以向服务端发送单词,服务端获取到单词后,在字典数据结构中搜索释义,然后处理之后传送给客户端
- 客户端获取到单词释义,进行打印操作,将释义展示出来!
这就是一个单词翻译的基本逻辑,接下来我们来实现一下:
2.2 设计字典类
现在我们从零设计字典类:
- 字典内部需要一个数据结构来储存单词与翻译的映射关系,可以使用哈希表来进行!
- 字典内部还需要配置文件的路径,方便创建时主动传入配置文件路径
- 构造时,根据配置文件中的内容快速建立映射关系
- 使用一个核心翻译接口,通过单词寻找到汉语释义
这里的配置文件可以是各式各样的,我这里使用的是如下格式的.txt文件:
hello: 你好,用作见面时的礼貌问候语 goodbye: 再见,分别时说的告别语 summer: 夏天,一年四季中的第二个季节,通常气候炎热 winter:冬天,一年四季中的最后一个季节,通常气候寒冷 ...
代码实现中会使用到文件流操作,这里使用的是C++风格的流操作,按行读取配置文件中的数据!
翻译接口使用的是简单的哈希表查询,不再赘述!
#include<unordered_map>
#include<string>
#include<fstream>
#include"Log.hpp"
using namespace log_ns;
//默认配置文件路径
const std::string gpath = "./dict.txt";
//文件间隔符
const std::string sep = ": ";
class Dict
{
private:
void LoadDict()
{
//建立文件流对象
std::fstream in(_path , std::ios_base::in);
if(!in.is_open())
{
LOG(FATAL , "The configuration file failed ! \n");
exit(0);
}
//进行读取
std::string line;
while(std::getline(in , line))
{
if(line.empty()) continue;
auto pos = line.find(sep);
if (pos == std::string::npos) continue;
std::string key = line.substr(0 , pos);
if(key.empty()) continue;
std::string value = line.substr(pos + sep.size());
if(value.empty()) continue;
_dict[key] = value;
LOG(DEBUG , "%s : %s load success\n", key.c_str() , value.c_str());
}
}
public:
Dict(const std::string& path = gpath) :_path(path)
{
LOG(DEBUG , "Dictionaries are being created! \n");
LoadDict();
}
std::string Translate(std::string str)
{
auto ret = _dict.<