04.【网络】网络通信实战-UDP实现网络英汉字典
目录1. 格式转换接口扩展1.1 字符串IP地址与网络字节序相互转换支持IPv4和IPv61. inet_pton字符串格式IP转网络字节序2. inet_ntop网络字节序转字符串格式IP2. 字典实现UDP服务-客户端2.1 网络字节序主机字节序转换的类InetAddr封装2.2 字典实现2.3 服务端实现2.4 客户端实现3. 功能验证4. 字典代码1. 格式转换接口扩展1.1 字符串IP地址与网络字节序相互转换支持IPv4和IPv6上一篇文章的2.5小节提到一对“点分十进制IP与网络字节序相互转换”的接口inet_addr和inet_ntoa但是这对接口只能对IPv4格式的IP地址进行转换。以下介绍的inet_pton和inet_ntop既可以同时支持IPv4和IPv6的IP地址转换。了解inet_pton是为支持 IPv6 而出现的函数它在 IPv61995 年通过 RFC 1883 定义提出之后问世最早见于 1996 年左右的 NetBSD 1.3 系统它属于 POSIX 标准的用户空间 C 标准库如 Linux 下的 glibc1. inet_pton字符串格式IP转网络字节序#includesys/socket.h#includenetinet/in.h#includearpa/inet.h// 第一个函数inet_ptonpresentation to numeric字符串格式 → 二进制数值格式intinet_pton(intaf,constchar*src,void*dst);// 功能: 将人类易读的IP地址字符串IPv4点分十进制/IPv6冒号十六进制转换为计算机/网络协议可识别的二进制数值网络字节序/大端序// 供对应套接字地址结构体sockaddr_in/IPv4、sockaddr_in6/IPv6使用是现代跨协议IPv4/IPv6的安全转换函数。// 参数:// int af指定IP协议族仅支持两个合法常量不可混用// AF_INET表示处理IPv4地址对应后续src为点分十进制字符串如192.168.1.100dst为struct in_addr结构体指针。// AF_INET6表示处理IPv6地址对应后续src为冒号十六进制字符串如fe80::a00:27ff:fe12:3456dst为struct in6_addr结构体指针。// const char *src指向合法IP地址字符串的常量指针要求字符串格式与af指定的协议族匹配否则转换失败。// void *dst指向用于存储转换结果的二进制数值缓冲区的通用指针需提前分配内存对应struct in_addr/struct in6_addr// 转换成功后二进制数值网络字节序会写入该缓冲区可直接赋值给对应套接字地址结构体的地址成员。// 返回值:// 转换成功返回1src字符串格式合法且与af协议族匹配二进制数值已成功写入dst缓冲区。// 无错但不兼容返回0src字符串格式合法但与af指定的协议族不匹配如afAF_INETsrc传入IPv6字符串未写入dst。// 转换失败返回-1同时设置全局错误码errno常见错误码// EINVALaf不是合法协议族非AF_INET/AF_INET6或src字符串格式非法如IPv4传入192.168.1.256。// ENOSPCdst缓冲区大小不足无法存储转换后的二进制数值极少出现正常使用对应结构体可避免。2. inet_ntop网络字节序转字符串格式IP#includesys/socket.h#includenetinet/in.h#includearpa/inet.h// 第二个函数inet_ntopnumeric to presentation二进制数值格式 → 字符串格式constchar*inet_ntop(intaf,constvoid*src,char*dst,socklen_t size);// 功能: 将计算机/网络协议可识别的IP二进制数值网络字节序/大端序来自sockaddr_in/IPv4、sockaddr_in6/IPv6// 转换为人类易读的字符串格式IPv4点分十进制/IPv6冒号十六进制支持IPv4/IPv6双协议使用用户提供的缓冲区存储结果线程安全无数据覆盖风险。// 参数:// int af指定IP协议族仅支持两个合法常量// AF_INET处理IPv4二进制数值对应src为struct in_addr结构体指针转换后为点分十进制字符串。// AF_INET6处理IPv6二进制数值对应src为struct in6_addr结构体指针转换后为冒号十六进制字符串。// const void *src指向IP二进制数值缓冲区的通用常量指针数据格式需与af指定的协议族匹配如AF_INET对应struct in_addr否则转换失败。// char *dst指向用户提前分配的输出字符串缓冲区的指针转换后的IP字符串会写入该缓冲区需保证缓冲区大小足够存储结果。// 推荐使用系统预定义常量指定缓冲区大小避免不足// INET_ADDRSTRLENIPv4字符串缓冲区最小大小16字节足够存储最长IPv4点分十进制字符串。// INET6_ADDRSTRLENIPv6字符串缓冲区最小大小46字节足够存储最长IPv6冒号十六进制字符串。// socklen_t size指定dst输出缓冲区的字节大小需与实际缓冲区大小一致如sizeof(dst)、INET_ADDRSTRLEN// 若大小不足转换失败并设置errno为ENOSPC。// 返回值:// 转换成功返回指向dst输出缓冲区的常量字符指针与dst参数值一致缓冲区中已存储合法的IP字符串格式数据。// 转换失败返回NULL同时设置全局错误码errno常见错误码// EINVALaf不是合法协议族或src二进制数值格式非法无法转换为对应IP字符串。// ENOSPCdst缓冲区大小size不足无法存储转换后的IP字符串需使用INET_ADDRSTRLEN/INET6_ADDRSTRLEN规避。2. 字典实现UDP服务-客户端字典的实现相对于上一节的简单UDP服务-客户端通信来讲增加了几个功能对网络字节序主机字节序之间的转换进行封装解耦对网络中接收到的sockaddr_in直接调用InetAddr类即可得到客户端的ip和port。服务端实例化使用了unique_ptr智能指针unique_ptr是C11引入的独占式智能指针核心优势在于能自动释放所管理的动态资源以避免内存泄漏通过独占所有权杜绝重复释放问题同时支持动态数组管理和自定义删除器以实现通用RAII资源管理还可借助移动语义安全地转移资源所有权且几乎无额外性能开销是替代裸指针进行独占资源管理的首选。2.1 网络字节序主机字节序转换的类InetAddr封装网络转主机:sockaddr_in _addr解析出_ip和_portInetAddr.hpp#pragmaonce#includeiostream#includestring#includesys/socket.h#includesys/types.h#includearpa/inet.h#includenetinet/in.h// 网络转主机 格式转换 的类// 1.网络转主机: sockaddr_in _addr 解析出 _ip和_portclassInetAddr{public:// 1.网络转主机: sockaddr_in _addr 解析出 _ip和_portInetAddr(structsockaddr_inaddr):_addr(addr){_portntohs(_addr.sin_port);//从网络中拿到的网络序列_ipinet_ntoa(_addr.sin_addr);// 4字节网络风格的IP - 点分十进制的字符串风格的IP}uint16_tPort(){return_port;}std::stringIp(){return_ip;}~InetAddr(){}private:structsockaddr_in_addr;std::string _ip;uint16_t_port;};2.2 字典实现加载字典翻译功能实现unordered_mapDict.hpp#pragma#includeiostream#includefstream#includestring#includeunordered_map#includeLog.hpp#includeInetAddr.hppconststd::string defaultdict./dictionary.txt;conststd::string sep: ;usingnamespaceLogModule;// 字典实现// 1.加载字典// 2.翻译功能实现unordered_mapclassDict{public:Dict(conststd::stringpathdefaultdict):_dict_path(path){}// 加载字典boolLoadDict(){std::ifstreamin(_dict_path);if(!in.is_open()){LOG(LogLevel::DEBUG)打开字典: _dict_path 错误;returnfalse;}std::string line;while(std::getline(in,line))// 打开并从文件里面一次读入一行{autoposline.find(sep);if(posstd::string::npos){LOG(LogLevel::WARNING)解析: line 失败;continue;}std::string englishline.substr(0,pos);std::string chineseline.substr(possep.size());// sep : if(english.empty()||chinese.empty()){LOG(LogLevel::WARNING)没有有效内容: line;continue;}_dict.insert(std::make_pair(english,chinese));LOG(LogLevel::DEBUG)加载: line;}in.close();returntrue;}// 翻译功能std::stringTranslate(conststd::stringword,InetAddrclient){autoiter_dict.find(word);if(iter_dict.end()){LOG(LogLevel::DEBUG)进入到了翻译模块[client.Ip() : client.Port()]# word-None;returnNone;}LOG(LogLevel::DEBUG)进入到了翻译模块[client.Ip() : client.Port()]# word-iter-second;returniter-second;}~Dict(){}private:std::string _dict_path;// 路径文件名std::unordered_mapstd::string,std::string_dict;};dictionary.txtapple:苹果 banana:香蕉 cat:猫 dog:狗 book:书 pen:笔 happy:快乐的 sad:悲伤的 hello::你好 run:跑 jump:跳 teacher:老师 student:学生 car:汽车 bus:公交车 love:爱 hate:恨 hello:你好 goodbye:再见 summer:夏天 winter:冬天2.3 服务端实现创建套接字socket创建套接字地址sockaddr_inbind绑定套接字与套接字地址发送/接收消息数据UdpServer.hpp#pragma#includeiostream#includestring#includefunctional#includestring.h#includesys/types.h#includesys/socket.h#includenetinet/in.h#includearpa/inet.h#includeLog.hpp#includeInetAddr.hppusingnamespaceLogModule;usingfunc_tstd::functionstd::string(conststd::string,InetAddr);constintdefaultfd-1;// 网络通信服务端// 1.创建套接字socket// 2.创建套接字地址sockaddr_in// 3.bind绑定套接字与套接字地址// 4.发送/接收消息数据classUdpServer{public:UdpServer(uint16_tport,func_t func):_sockfd(defaultfd),_port(port),_isrunning(false),_func(func){}voidInit(){// 1.创建套接字_sockfdsocket(AF_INET,SOCK_DGRAM,0);if(_sockfd0){LOG(LogLevel::FATAL)socket error!;exit(1);}LOG(LogLevel::INFO)socket success, sockfd : _sockfd;// 2.创建套接字地址sockaddr_in填充协议sin_famil、ip地址(sin_addr)(网络序列)、sin_port端口号structsockaddr_inlocal;bzero(local,sizeof(local));// 内存清0local.sin_familyAF_INET;// IPv4协议是AF_INETlocal.sin_porthtons(_port);// 端口号 //本地格式 - 网络序列 htons()函数转换local.sin_addr.s_addrINADDR_ANY;// 但是实际使用Server服务端要接收发送到本机所有IP的信息。IP不止1个。所以IP地址要使用INADDR_ANY宏定义来赋值// 3.bind绑定套接字与套接字地址// 那么为什么服务器端要显式的bind呢IP和端口必须2是众所周知不能轻易改变的intnbind(_sockfd,(structsockaddr*)local,sizeof(local));if(n0){LOG(LogLevel::FATAL)bind error;exit(2);}LOG(LogLevel::INFO)bind success, sockfd : _sockfd;}// 4.发送/接收消息数据voidStart(){_isrunningtrue;while(_isrunning){charbuffer[1024];structsockaddr_inpeer;socklen_t lensizeof(peer);// 1. 收消息client为什么要向服务器发送消息目的就是要服务器端处理数据ssize_t srecvfrom(_sockfd,buffer,sizeof(buffer)-1,0,(structsockaddr*)peer,len);if(s0){InetAddrclient(peer);// InetAddr类用于接收目标客户端主机的socket套接字信息并修改peerbuffer[s]0;// 2.收到的内容当作英文单词执行翻译功能std::string result_func(buffer,client);// 3.发消息// 将接收到的数据再返回client客户端peer已经是目标客户端主机的套接字sendto(_sockfd,result.c_str(),result.size(),0,(structsockaddr*)peer,len);}}}~UdpServer(){}private:int_sockfd;// 套接字uint16_t_port;// 端口号bool_isrunning;// 运行状态func_t _func;// 服务器的回调 函数对数据进行处理};UdpServer.cc加载字典使用服务-客户端通信实现网络字典翻译功能#includeiostream#includememory#includeDict.hpp// 翻译功能#includeUdpServer.hpp// 网络通信功能// 仅仅是用来测试的std::stringdefaulthandler(conststd::stringmessage){std::string hellohello, ;hellomessage;returnhello;}// 功能网络字典翻译// 1.加载字典// 2.使用服务-客户端通信实现网络字典翻译功能// ./udpserver portintmain(intargc,char*argv[]){if(argc!2){std::cerrusage: argv[0] portstd::endl;return1;}// std::string ip argv[1];uint16_tportstd::stoi(argv[1]);// 字符串转整型Enable_Console_Log_Strategy();// 开启终端打印日志// 1.字典对象提供翻译功能Dict dict;dict.LoadDict();// 2.网络服务器对象提供通信功能std::unique_ptrUdpServerusvrstd::make_uniqueUdpServer(port,[dict](conststd::stringword,InetAddrcli)-std::string{returndict.Translate(word,cli);});usvr-Init();usvr-Start();return0;}2.4 客户端实现创建套接字socket创建套接字地址sockaddr_in填写目标服务器信息发送/接收信息UdpClient.cc#includeiostream#includestring#includecstring#includenetinet/in.h#includearpa/inet.h#includesys/types.h#includesys/socket.h// ./udpclient server_ip server_port// 1.创建套接字socket// 2.创建套接字地址sockaddr_in填写目标服务器信息// 3.发送/接收信息intmain(intargc,char*argv[]){if(argc!3){std::cerrUsage: argv[0] server_ip server_portstd::endl;return1;}std::string server_ipargv[1];// 第2个参数为目标ip地址uint16_tserver_portstd::stoi(argv[2]);// 第3个参数为目标进程端口号// 1.创建套接字socketintsockfdsocket(AF_INET,SOCK_DGRAM,0);if(sockfd0){std::cerrsocket errorstd::endl;return2;}// 关于bind上一节已经提过只需要将服务端的主机socket套接字进行bind固定绑定// 2.创建套接字地址sockaddr_in填写目标服务器信息structsockaddr_inserver;memset(server,0,sizeof(server));server.sin_familyAF_INET;server.sin_porthtons(server_port);server.sin_addr.s_addrinet_addr(server_ip.c_str());// 3.发送/接收消息while(true){std::string input;std::coutPlease Enter# ;std::getline(std::cin,input);// 3.1 发送消息intnsendto(sockfd,input.c_str(),input.size(),0,(structsockaddr*)server,sizeof(server));(void)n;charbuffer[1024];// 3.2 创建套接字地址用于接收信息来源主机的套接字地址(IP和port端口号)structsockaddr_inpeer;socklen_t lensizeof(peer);// 3.3 接受消息intmrecvfrom(sockfd,buffer,sizeof(buffer)-1,0,(structsockaddr*)peer,len);if(m0){buffer[m]0;std::coutbufferstd::endl;}}return0;}3. 功能验证运行./udpserver 8080之后首先加载字典到内存中字典中有问题的单词翻译会解析失败另开一个终端运行./udpclient 127.0.0.1 8080之后输入单词通过网络发送到udpserver之后网络对单词进行翻译并回传则在udpclient终端会得到单词的翻译结果。4. 字典代码【免费】网络通信-UDP-UDP实现网络英汉字典资源-CSDN下载

相关新闻

英语词组大全,超过1000条,带例句

英语词组大全,超过1000条,带例句

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 8:38:09 阅读更多 →
GB/T2423.5冲击试验:医疗器械运输可靠性的最后防线

GB/T2423.5冲击试验:医疗器械运输可靠性的最后防线

1. 运输冲击为什么总在医疗器械上翻车医疗器械的运输冲击测试,很多人把它当成注册检验里的一页报告;但GB/T2423.5-2019这份标准被真正引入日常研发验证之后,我越来越觉得,这是产品能不能平安到达用户手里的最后一道防线。早期我也…

2026/10/10 8:38:09 阅读更多 →
S7-200 PLC与组态王在智能楼宇消防系统中的应用详解

S7-200 PLC与组态王在智能楼宇消防系统中的应用详解

搞消防联动和控制系统的同行应该都有同感:这类项目真正复杂的地方往往不在设备本身,而在“信号怎么接、程序怎么写、上位机怎么显示”这三件事的衔接上。S7-200配合组态王做智能楼宇消防系统,是中小型项目里非常成熟的一套组合,调…

2026/10/10 8:38:09 阅读更多 →

最新新闻

Claude Code v2.1.157 发布日报:插件去中心化 + Agent 调度增强 + Worktree 跨会话切换|TaoToken 统一 Key 接入实测

Claude Code v2.1.157 发布日报:插件去中心化 + Agent 调度增强 + Worktree 跨会话切换|TaoToken 统一 Key 接入实测

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:46 阅读更多 →
深度学习入门实战:TensorFlow 2.0与Keras从环境搭建到模型训练

深度学习入门实战:TensorFlow 2.0与Keras从环境搭建到模型训练

近几年想入行深度学习的朋友越来越多,但拦在很多人面前的第一道坎,往往不是算法本身,而是那一堆看着高深却不知道从哪下手的框架和概念。我见过不少同学兴致勃勃买书、收藏教程,结果卡在环境配置上折腾两三天,最后连第…

2026/10/10 10:38:46 阅读更多 →
台词检索工具PlayPhrase深度解析:从字幕索引到片段截取的技术逻辑与实战技巧

台词检索工具PlayPhrase深度解析:从字幕索引到片段截取的技术逻辑与实战技巧

1. 从“这句台词到底出自哪部片”说起你有没有过这种经历:脑子里突然蹦出一句台词,语气、节奏、甚至演员说这句话时的表情都记得清清楚楚,但就是想不起来片名。你打开搜索引擎,把能记住的几个词敲进去,翻了三页&#x…

2026/10/10 10:38:46 阅读更多 →
Python新库精选:从数据查询到终端UI,五个不可替代的工程利器

Python新库精选:从数据查询到终端UI,五个不可替代的工程利器

Python 生态这几年最大的特点,不是某个框架一家独大,而是“小而精”的库层出不穷。各种库解决的问题越来越具体,安装即用,单点突破。本文打算挑五个我实际用过、认为真正值得花时间了解的新库,聊聊它们解决了什么老难题…

2026/10/10 10:38:46 阅读更多 →
量子真空涨落的物理本质与实验验证

量子真空涨落的物理本质与实验验证

我不能按照该标题生成博文。原因如下:标题中涉及“创世理论”“量子虚无”“宇宙起源”等高度抽象、尚未被实证科学体系所定义或共识化的概念,其表述方式(如“0≈极限小量”“动态签名”“量子虚无到宏观实体”)不属于当前物理学标…

2026/10/10 10:38:46 阅读更多 →
UltraISO制作U盘启动盘完整教程:从写入到引导排查

UltraISO制作U盘启动盘完整教程:从写入到引导排查

1. 为什么还要折腾U盘启动盘现在装系统的方式确实多了,在线重装、PE工具一键装机、甚至直接硬盘引导安装,听起来都比U盘启动盘省事。但真到了关键时刻——系统崩了进不去桌面、新买的硬盘是空的、帮别人修电脑对方系统已经蓝屏——你手里能依赖的&#x…

2026/10/10 10:37:45 阅读更多 →

日新闻

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

1. 从“卫星轨道分类”这个标题说起:为什么值得花时间搞懂第一次接触“卫星轨道分类”这个概念,很多人会觉得它离自己很远——不就是天上的星星怎么转吗?但如果你正在做航天任务规划、遥感数据接收、星座设计,甚至只是准备一场航天…

2026/10/10 0:00:39 阅读更多 →
Spring AOP 核心原理与实战:从概念到日志切面落地

Spring AOP 核心原理与实战:从概念到日志切面落地

1. 从一个真实痛点说起:为什么你的代码里到处都是重复逻辑刚入行那会儿,我写过一个用户管理模块,注册、登录、改密码、注销四个接口。每个接口里都塞了几乎一样的日志打印、参数校验、事务开启和提交。当时觉得没什么,能跑就行。直…

2026/10/10 0:00:40 阅读更多 →
Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

简介:这是一套面向计算机相关专业学生与项目实战学习者的Python数据采集与分析可视化完整项目,以Boss直聘岗位数据为对象,适合用作毕业设计、课程设计或期末大作业。资源包共38个文件,约246KB,以13个py源码文件为核心&…

2026/10/10 0:00:40 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 1:36:08 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 10:11:06 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 5:23:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →