当前位置: 首页 > news >正文

【Linux网络】Socket编程实战,基于UDP协议的Dict Server

前言:

        上文我们实现了对于基于UDP的EchoServer的Socket编程。【Linux网络】Socket编程实战,基于UDP协议的Echo Server-CSDN博客

        我们再进一步优化更新其功能,使其实现一个翻译功能!


翻译模块

        首先,我们通过上文的代码实现。我们发现若是想要实现单词翻译功能,我们只需要单词实现翻译模块功能。

        客户端、服务端的创建套接字、bind、收发消息等等功能是不需要变的。我们只需要对客户端发来的信息做翻译处理即可!既在服务端中实现对翻译功能的调用。

TXT文件

        首先,我们先创建一个.txt文本,用于规定翻译的文本范围

Dict.txt

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

翻译模块实现

//Dict.hpp#include <iostream>
#include <string>
#include <fstream>
#include <unordered_map>
#include "Log.hpp"
using namespace LogModule;const std::string DefaultPath = "./Dict.txt";
const std::string step = ": ";class Dict
{
public:Dict(const std::string &path = DefaultPath): _path(path){}void LoadDict(){// 打开对应文件std::ifstream inFile;inFile.open(_path, std::ios::in);// 如果没有打开成功if (!inFile) // 等价于:!inFile.is_open(){LOG(LogLevel::FATAL) << "文件打开失败!";return;}// 加载字典数据string line;// 读取文件中一整行内容(cin则只读取到空格)while (getline(inFile, line)){// 找到分隔符的位置auto pos = line.find(step);// 没有找到if (pos == std::string::npos){LOG(LogLevel::DEBUG) << "单词解析失败!";}// 获取中英文std::string English = line.substr(0, pos);std::string Chinese = line.substr(pos + step.size());if (English.empty() || Chinese.empty()){LOG(LogLevel::DEBUG) << "单词信息残缺!";}// 插入map中_umap.insert(make_pair(English, Chinese));LOG(LogLevel::INFO) << "单词载入成功!";}// 关闭对应文件inFile.close();}string Translate(const std::string &word){auto pos = _umap.find(word);if (pos == _umap.end()){return word + " -> None";}else{std::string ss = pos->second;return word + " -> " + ss;}}private:std::string _path;unordered_map<std::string, std::string> _umap;
};

服务器调用翻译模块

        先在UdpServer.cc中创建、初始化翻译模块对象,并传入对应方法。

//UdpServer.cc#include "UdpServer.hpp"
#include <cstdlib>
#include "Dict.hpp"// 给出 端口号
int main(int argc, char *argv[])
{if (argc != 2){std::cout << "Please use: " << argv[0] << " PORT" << endl;}else{Dict dict;dict.LoadDict();uint16_t port = stoi(argv[1]); // 注:字符串转整数udpserver us(port, [&dict](std::string word){ return dict.Translate(word); });us.Init();us.Start();}
}

        随后UdpServer.hpp中直接调用该方法即可!

完整代码

客户端

//UdpClient.cc#include "Log.hpp"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>
#include <cstdlib>
#include <iostream>
using namespace LogModule;// 给出 ip地址 端口号
int main(int argc, char *argv[])
{if (argc != 3){std::cout << "Please use: " << argv[0] << " IP " << "PORT " << endl;exit(1);}uint32_t ip = inet_addr(argv[1]); // 注:字符串转合法ip地址uint16_t port = stoi(argv[2]);    // 注:字符串转整数// 创建套接字int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0){LOG(LogLevel::FATAL) << "创建套接字失败";exit(1);}LOG(LogLevel::INFO) << "创建套接字";// 绑定?不用显示绑定,OS会自动的绑定// 填写服务器信息struct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;local.sin_addr.s_addr = ip;local.sin_port = htons(port);// 一定是死循环while (true){// 向服务器发送信息cout << "Please Cin # ";std::string buff;cin >> buff;// std::getline(std::cin, buff);// buff.size()-1 会丢失最后一个字符,应改为 buff.size()ssize_t s = sendto(sockfd, buff.c_str(), buff.size(), 0, (struct sockaddr *)&local, sizeof(local));if (s < 0){LOG(LogLevel::WARNING) << "向服务器发送信息失败";exit(1);}// 接收服务器返回的信息char buffer[1024];memset(&buffer, 0, sizeof(buffer));struct sockaddr_in peer;socklen_t len = sizeof(peer);ssize_t ss = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&peer, &len);if (ss < 0){LOG(LogLevel::WARNING) << "接收服务器信息失败";exit(1);}printf("%s\n", buffer);memset(&buff, 0, sizeof(buffer)); // 清理缓存}
}

服务端

//UdpServer.cc#include "UdpServer.hpp"
#include <cstdlib>
#include "Dict.hpp"// 给出 端口号
int main(int argc, char *argv[])
{if (argc != 2){std::cout << "Please use: " << argv[0] << " PORT" << endl;}else{Dict dict;dict.LoadDict();uint16_t port = stoi(argv[1]); // 注:字符串转整数udpserver us(port, [&dict](std::string word){ return dict.Translate(word); });us.Init();us.Start();}
}
//UdpServer.hpp#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <functional>
#include "Log.hpp"
#include "InetAddr.hpp"
using namespace LogModule;class udpserver
{using func_t = function<string(string)>;public:udpserver(uint16_t port, func_t func)// : _addr(inet_addr(addr.c_str())), // 注:直接将其转换为合法的ip地址: _port(port),_func(func){_running = false;}// 初始化:1.创建套接字 2.填充并绑定地址信息void Init(){// 1.创建套接字// 返回套接字描述符 地址族 数据类型 传输协议_sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (_sockfd < 0){LOG(LogLevel::FATAL) << "创建套接字失败!";exit(1);}LOG(LogLevel::INFO) << "创建套接字";// 2.绑定信息// 2.1填充信息struct sockaddr_in local;// 将指定内存块的所有字节清零bzero(&local, sizeof(local));local.sin_family = AF_INET; // IPv4地址族// local.sin_addr.s_addr = _addr;   //IP地址(主机序列转化为网络序列)local.sin_addr.s_addr = INADDR_ANY; // 赋值为INADDR_ANY,表示任意地址local.sin_port = htons(_port);      // 端口号// 2.2绑定信息int n = bind(_sockfd, (struct sockaddr *)&local, sizeof(local));if (n < 0){LOG(LogLevel::FATAL) << "绑定失败";exit(1);}LOG(LogLevel::INFO) << "绑定成功";}// 启动运行:一直运行不停止;1.接收客户端的信息 2.对客户端发送来的信息进行回显void Start(){// 一定是死循环_running = true;while (_running){// 接收客户端的信息char buff[1024];struct sockaddr_in peer;unsigned int len = sizeof(peer);// 套接字描述符,数据存放的缓冲区,接收方式:默认,保存发送方的ip与端口,输入输出参数:输入peer的大小,输出实际读取的数据大小ssize_t s = recvfrom(_sockfd, buff, sizeof(buff) - 1, 0, (struct sockaddr *)&peer, &len);// 显示发送方的ip与protInetAddr iaddr(peer);cout << iaddr.ip() << " : " << iaddr.prot() << " : ";// 显示发送的信息buff[s] = 0;printf("%s\n", buff);// 回显消息if (s > 0){// 调用自定义方法std::string ss = _func(string(buff));// 将数据发送给客户端// 套接字描述符,要发送的信息,发送方式:默认,接收方的ip与端口信息ssize_t t = sendto(_sockfd, ss.c_str(), ss.size(), 0, (struct sockaddr *)&peer, len);if (t < 0){LOG(LogLevel::WARNING) << "信息发送给客户端失败";}}memset(&buff, 0, sizeof(buff)); // 清理缓存}}private:int _sockfd;uint32_t _addr;uint16_t _port;bool _running;// 回调方法func_t _func;
};
//InetAddr.hpp#include <iostream>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string>// 实现网络地址与主机地址的转换class InetAddr
{
public:InetAddr(struct sockaddr_in &addr): _addr(addr){_prot = ntohl(_addr.sin_port);   // 网络地址转主机地址_ip = inet_ntoa(_addr.sin_addr); // 将4字节网络风格的IP -> 点分十进制的字符串风格的IP}uint16_t prot(){return _prot;}string ip(){return _ip;}private:struct sockaddr_in _addr;uint16_t _prot;std::string _ip;
};

http://www.dtcms.com/a/592949.html

相关文章:

  • web京东商城前端项目4页面
  • 15、Linux 打包压缩命令
  • 网站后台源代码更改营销广告策划方案
  • 数据库迁移革命:金仓KReplay如何用真实负载回放技术缩短3周测试周期
  • 网站开发搭建合同范本企业软件解决方案
  • Java 中 Arrays.sort() 的底层实现
  • MPAndroidChart 双柱分组图:解决 X 轴标签无法居中问题及 UI 宽度计算指南
  • 政务外网终端一机两用安全管控解决方案
  • 数字华容道游戏
  • M4-R1 开源鸿蒙(OpenHarmory)开发板丨串口调试助手实战案例
  • 建材做网站好吗破解插件有后门wordpress
  • 旅游网站建设流程步骤怎么自己做礼品网站
  • C语言--文件读写函数的使用,对文件读写知识有了更深的了解。C语言--文件读写函数的使用,对文件读写知识有了更深的了解。
  • 数据结构示例代码
  • 数字化工厂:基于层级模型的智能制造新范式
  • C语言--变量(全局变量、局部变量、初始化)
  • 羊驼送洗后因毛发未吹干致失温死亡,物联网技术助力防范宠物洗澡失温事故
  • Raylib 基本绘图操作
  • (Arxiv-2025)BINDWEAVE:通过跨模态整合实现主体一致性的视频生成
  • 怎么做会员积分网站建网站商城有哪些公司
  • 网站如何验证登陆状态广州专业做网页的公司
  • MySQL的增删改查功能合集
  • Oracle数据块编辑工具( Oracle Block Editor Tool)-obet
  • 什么是量子纠缠?大白话
  • 用服务器自建 RustDesk 远程控制平台
  • 新手做网站如何被百度快速收录教程
  • 基于java技术的田径俱乐部网站的设计与实现
  • 第二十四篇:C++模板元编程入门:constexpr与type_traits的编译期魔法
  • C语言数组作为函数参数(3种写法,附带实例)
  • SPARQL文档导读