【Linux网络编程】--UDP__SCOKE
下面我们先对服务器端进行封装。一、简单回显服务器我们要实现一个简单回显服务器和客服端的数据回显客户端进行发送消息服务器收到消息后再将这个消息回显给我们的用户端。就类似我们在Linux上使用的echo指令。整个程序的核心就是套接字的相关接口还有使用UDP协议进行实现。首先我们需要两个部分一个是服务器端用户端。如上所示。下面我们先对服务器端进行封装。EchoServer.hpp1、初始化Init首先对于一个服务器我们初始时要对其进行初始化操作然后再去启动那么我们需要一个Init接口然后初始化完成我们再进行启动所以还需要一个启动接口Start前面我们学习系统部分的时候讲到Linux下一切皆文件不论我们是使用UDP还是使用TCP那么我们进行网络通信前都要将网络文件先打开那么我们要打开一个网络文件要使用下面这个接口要使用其要包含头文件sys/socket.h下面我们来看其返回值其返回值是一个整数那么其返回值打开成功那么就返回的是一个文件描述符fd。然后失败返回-1并且会设置其错误信息。下面是对其参数的认识首先是domain其是一个域其实就是我们未来创建这个网络文件这个文件的使用范围就比如我们是要进行本地通信还是跨网络通信如上所示如果我们想要的是本地通信那么就传入AF_UNIX如果是网络通信那么就传入AF_INET。其他的我们不需要太过关心。然后是type这个参数就是确定我们通信的类型就比如说是我们的字节流还是用户数据报的方式。第三个参数就是我们要使用的那种协议就比如是使用UDP协议还是TCP协议但是前面第二个参数设置好了那么通信的协议基本就确定了所以一般这个参数我们设置为0.所以对于socket的参数我们设置的也基本是固定的第一个参数我们设置为AF_INET第二个参数就在S0CK_STREAM和SCOK_DGRAM上选择第三个参数就设置为0即可。所以就只有第二个参数是变化的那么其第一个就是我们的TCP第二个就是UDP。所以未来我们的服务器端需要一个文件描述符表示我们打开的网络文件的fd。如上我们就可以将一个网络文件套接字创建了那么对于错误信息的输出我们可以引入前面我们写的日志系统进行打印。那么我们上面将创建好的网络文件的文件描述符进行打印那么其文件描述符肯定为3那么我们初始化首先要创建一个套接字socke他那么其本质上就是创建一个网络文件。那么我们的网络有其IP信息还有其端口号那么我们也要将其进行设置那么我们的成员变量还要设置一个ip和端口号但是有个问题就是我们前面所看到的端口号是192.1.1.0这种样式的这个叫做字符串类型的IP但是我们发现其是由4个整数和三个点组成的这种IP地址为字符串风格的点分十进制IP地址是让人看的。那么其大小就要达到32字节了所以在网络端其是会转换成4字节IP的。如上就是我们的IP和端口号对于服务器来说其_port必须是固定的。这个是由用户进行设置的。未来在使用上我们希望其和我们在Linux下使用一样./server_udp ip port这个样式进行使用那么在我们的主程序中我们可以如下进行设置这个是描述网络socket的结构体可以看到其中包括了sin_port这个就是我们的端口号然后还有的就是sin_addr这个就是我们的id。后面是sin_zero是填充字段我们不需要关注。然后其还包含了AF_INET但是有个疑问了就是我们创建socket的时候就已经传入了AF_INET了那么为啥我们这边也要有呢这是给我们后续使用别的函数接口的时候进行判断使用的。但是我们发现上面的结构体并没有出现AF_INET其实是在第一个那个宏定义中其就被替换成下面的东西然后上面的##在宏中其会将两边的进行拼接那么我们传入的sin_那么就会被替换成sin_family那么总的就是sa-family_t sin_famliy。这个数据类型实际上就是一个无符号长整型。所以我们对于网络信息的填充如下然后有个问题就是这个数据是否已经存在我们打开的网络文件呢实际上并没有所以下面我们还需要将这个信息和我们打开的socket进行绑定。首先发送方的IP和port都要带入到网络中 所以我们在服务器端要将IP和port进行处理。如下下面进行socket和网络信息进行绑定。要使用下面这个接口首先第一个参数就是我们要进行绑定的socket返回值一样成功返回0失败返回-1并且设置错误信息。第二个参数我们发现是一个struct sockaddr类型的结构体那么我们需要将我们的信息进行强制类型转换第三个参数就是我们的长度。如下所以总的初始化代码如下void Init() { // 第一步创建套接字socket本质就是打开一个网络文件 _socketfd socket(AF_INET, SOCK_DGRAM, 0); if (_socketfd 0) { LOG(LogLevel::FATAL) create socket error; exit(SOCKET_ERR); } LOG(LogLevel::INFO) create scoket success,socket: _socketfd; // 第二步设置网络信息IP, struct sockaddr_in local; bzero(local, sizeof(local)); local.sin_family AF_INET; local.sin_addr.s_addr inet_addr(_ip.c_str()); local.sin_port htons(_port); // 第三步,将信息设置到socket中 int n bind(_socketfd, (struct sockaddr *)local, sizeof(local)); if(n0) { LOG(LogLevel::FATAL)create socket error; exit(BIND_ERR); } LOG(LogLevel::INFO)bind socket success,ip:_ipport:_port; }2、运行Start在服务器运行中其实际上是一个死循环但是对于数据的发送和接收其不再是前面的字节流文件流等所以我们使用下面的函数首先是其返回值就是我们所读到多少字节的数据。失败就返回-1。下面我们来看其参数第一个参数scokfd就是我们要绑定的那个网络文件。第二个参数其是一个缓冲区未来就是用来存放我们收到的数据的实际上是一个void*类型 的那么其未来可以接收不同类型的数据。第三个参数size_t len就设置为我们缓冲区的长度即可。第四个参数就是我们要其阻塞读取还是非阻塞读取我们就设置为0阻塞读取即可。第五个参数和上面使用bind的类似。用来获取对方ip和port的数据第六个参数和bind的第三个参数一样补充未来我们获取对方的发送的信息的时候那么我们不仅需要信息本身还需要获取到发送方是谁方便后续回复所以需要第五个参数获取发送方的IP和prot。代码如下对于收信息错误我们并不需要退出。上面我们对于数据我们先认为传递的是字符串。那么我们服务器端接收到消息那么就要将这个消息发送给接收方用户。那么就要使用到下面这个接口首先其返回值其失败的话也是返回-1成功那么就会返回发送的字节数。对于发送数据的问题有下面三个疑问首先是我们要发送什么数据然后我们要发送给谁如何发送给对方。那么在这个发送函数中也要我们传入一个缓冲区就是第二个参数。那么发送给谁那么就是发送给对方的IPprot。那么就是最后两个参数。发送的方式是通过对应的sockfd决定。我们接收到消息的时候对方也传入了其对应的IP和prot所以我们可以如下使用代码如下void Start() { char inbuffer[1024]; while (true) { struct sockaddr_in peer; socklen_t lensizeof(peer); ssize_t nrecvfrom(_socketfd,inbuffer,sizeof(inbuffer)-1,0,(struct sockaddr*)peer,len); if(n0) { inbuffer[n]0; LOG(LogLevel::DEBUG)cilent say#inbuffer; std::string echo_stringserver echo#; echo_stringinbuffer; sendto(_socketfd,echo_string.c_str(),echo_string.size(),0,(struct sockaddr*)peer,len); } else { LOG(LogLevel::ERROR)recvform error; } } }如上对于服务器端的设计就大致完成了。EchoClient.cc首先我们的客户端需要进行网络通信那么其也需要创建一个网络文件那么其也得进行网络文件的创建那么我们的用户端的socket就创建好了下面我们的用户端也要有其对应的IP和port这是在网络中标识自己的唯一标志。但是要注意的是我们对于客户端的bind不要去显示bind这是为啥呢因为对于服务端其未来是1n的情况那么我们服务端的端口号一般是固定的。但是对于用户端我们对其是多少并不关心其只需要存在就可以。并且未来用户端也会打开多个服务端那么如果显示绑定那么可能会出现端口号冲突的问题。所以对于用户端我们使用随机端口的方式由OS进行选择。而且我们发现日常使用软件的时候都是先给服务端进行数据发送所以OS底层会隐式自动进行获取随机端口然后进行bind IP和prot。下面我们完成对用户端的消息发送首先我们要获取到用户的输入但是有个问题我们得知道要进行通信的服务器所以这个要我们的用户进行输入所以在使用这个程序前我们要告诉用户输入对于服务器的IP和prot。但是有个问题就是我们用户又是如何知道对方的IP和prot的呢这个信息是内置到客户端中的是直接包含在内的。所以我们是直接进行硬编码的。上面我们就把发送方式还有发送的数据是啥搞定下面就是发送给谁了所以我们还需要一个struct socket_in 结构体变量。未来我们的发送方要将服务端的IP和prot也要发送给服务器所以其IP和prot也要转换为网络序列的。给服务器端发送完数据后那么就要接收服务器端发送来的数据了。下面我们来测试两个端口是否能够进行通信。首先我们先来进行本地通信那么在对于本地通信那么在输入IP的时候要设置为127.0.0.1然后对于端口号我们可以先随便设置下面我们设置为8080。上面我们使用的127.0.0.1IP地址其是本地环回地址其只是将数据在协议栈中走一遍不会经过网络。可以用于本地通信或者网络代码的测试。那么我们要通过网络进行数据交流又如何操作呢首先我们先补充下面几个问题1、云服务器的公网IP是禁止被显示bind的2、在服务器开发的时候不建议用户显示bind的IP地址3、云服务器的公网IP是禁止被bind的但是并不是不能被使用在我们的云服务器中是存在多个IP地址的如果我们的服务器bind了IP那么其未来只能和这个IP的机器进行通信了但是未来我们的服务器是要和多个IP的用户进行通信的所以这也是为啥不能显示bind其IP。所以我们是需要服务器和任意IP绑定主要其端口号一样即可。所以我们将服务器端的IP绑定的IP进行设置为INADDR_ANY。那么下面我们再来运行看看可以看到服务器端和用户端此时可以进行通信在我们的服务器端我们也要将用户端的IP和prot获取下来所以我们在收到用户数据的时候要在服务器端进行获取。未来我们的服务器是会被多个用户访问的所以我们可以将这些用户进行管理。下面我们来认识一个指令netstat那么其可以把我们当前机器中和网络和通信相关的信息打印出来。其有如下选项二、简单的英译汉的⽹络字典上面我们实现的是实现网络中进行通信但是没有任何的业务所以下面我们将上面的对于数据进行翻译处理。上面我们对于收到数据对于数据的处理也放在了服务器端那么下面我们想让服务器只负责数据的收发而数据的处理交给别的层次去进行。代码如下#pragma once #include iostream #include string #include unordered_map using namespace NS_LOG_MODULE; static const std::string default_dict ./dict.txt; static const std::string sep : ; // 分隔符 class Dict { public: Dict(const std::string dict_path default_dict) : _dict_path(dict_path) { LoadDict(); } ~Dict() {} void LoadDict() { std::ifstream in(_dict_path); if (!in.is_open()) { LOG(LogLevel::FATAL) open _dict_path error; exit(1); } std::string line; while (std::getline(in, line)) { LOG(LogLevel::FATAL) load: line success; auto pos line.find(sep); if (pos std::string::npos) { LOG(LogLevel::WARNING) Format: line success; continue; } std::string k line.substr(0, pos); std::string v line.substr(pos sep.size()); _dict.insert(std::make_pair(k, v)); } in.close(); } std::string Translate(std::string word) { auto iter _dict.find(word); if (iter ! _dict.end()) { return iter-second; } else { return None; } } private: std::string _dict_path; std::unordered_mapstd::string, std::string _dict; };三、多用户的服务器上面我们的服务器和用户端我们发现用户端都是单用户的所以下面我们可以通过多线程的方式实现。那么我们服务器端将用户进行管理起来多各个用户进行任何的收发。我们可以将前面写的线程池引入我们的服务器端将数据发送到线程池通过线程池进行任务的转发。后续我们服务端对于用户端的管理我们对于IP和prot进行管道来确定用户的唯一性。代码如下#pragma onec #include iostream #include string #include vector #include InetAddr.hpp #include Logger.hpp using namespace NS_LOG_MODULE; class UserManager { public: UserManager() { } void AddUser(const InetAddr addr) { if (SearchUser(addr)) { return; } _users.push_back(addr); } void DelUser(const InetAddr addr) { if (!SearchUser(addr)) { return; } for (auto iter _users.begin(); iter ! _users.end(); iter) { if (*iter addr) { _users.erase(iter); break; } } } bool SearchUser(const InetAddr addr) { for (auto users : _users) { if (users addr) { return true; } } return false; } bool ModUser(const InetAddr addr) { DelUser(addr); AddUser(addr); } ~UserManager() { } private: std::vectorInetAddr _users; };这是对多用户进行管理的部分。那么我们服务器的对于数据转发到我们的用户所以下面我们再设置一个路由转发的功能代码如下#pragma once #includeiostream #includestring #includememory #includesys/socket.h #includeMutex.hpp #includeUserManager.hpp class Route { public: Route() :_uma(std::unique_ptrUserManager()) { } void CheckUser(const InetAddr addr) { LockGuard lockguard(_lock); _uma-AddUser(addr); } void OfflineUser(const InetAddr addr) { LockGuard lockguard(_lock); _uma-DelUser(addr); } void Broadcast(int sockfd,std::string message) { LockGuard lockguard(_lock); auto users_uma-Users(); for(auto user:users) { sendto(sockfd,message.c_str(),message.size(),0,(struct sockaddr*)user.GetNetAddress(),user.Len()); } } ~Route(); private: std::unique_ptrUserManager _uma; Mutex _lock; };

相关新闻

NoSleep防休眠工具完整指南:告别Windows自动锁屏的终极解决方案

NoSleep防休眠工具完整指南:告别Windows自动锁屏的终极解决方案

NoSleep防休眠工具完整指南:告别Windows自动锁屏的终极解决方案 【免费下载链接】NoSleep Lightweight Windows utility to prevent screen locking 项目地址: https://gitcode.com/gh_mirrors/nos/NoSleep 还在为Windows系统频繁自动锁屏而烦恼吗&#xff1…

2026/8/5 9:29:03 阅读更多 →
ARIMA时间序列预测:从原理到Python实战的完整指南

ARIMA时间序列预测:从原理到Python实战的完整指南

1. 项目概述:从业务痛点理解ARIMA模型的价值做数据分析或者业务预测的朋友,估计都遇到过这样的场景:老板让你预测下个季度的销售额,或者运维同事需要预估服务器下周的流量峰值。你手头只有一串按时间顺序排列的历史数据&#xff0…

2026/8/5 9:29:03 阅读更多 →
零成本接入Grok等AI模型:Chatbox与社区API实战指南

零成本接入Grok等AI模型:Chatbox与社区API实战指南

想用最新的 AI 模型,但被高昂的 API 费用、复杂的部署流程和严格的访问限制劝退?这几乎是每个开发者和 AI 爱好者的共同痛点。今天要聊的,不是某个单一的模型,而是一个能让你在手机和电脑上,几乎“零门槛”接入包括 Gr…

2026/8/5 9:29:03 阅读更多 →

最新新闻

AI做付费专栏的底层逻辑(92%从业者忽略的3个致命认知陷阱)

AI做付费专栏的底层逻辑(92%从业者忽略的3个致命认知陷阱)

更多请点击: https://intelliparadigm.com 第一章:AI做付费专栏的底层逻辑(92%从业者忽略的3个致命认知陷阱) AI驱动的付费专栏不是“把课程搬上网”,而是重构知识交付的价值链。多数人误将AI当作内容生成工具&#x…

2026/8/5 14:23:22 阅读更多 →
列出网站开发建设的步骤:从0到1打造高转化企业官网的实战指南

列出网站开发建设的步骤:从0到1打造高转化企业官网的实战指南

在这个数字化浪潮席卷全球的今天,网站已经不再仅仅是一个展示企业形象的“电子名片”,它是企业的第二生命线,是24小时不间断工作的销售冠军,更是品牌与用户建立信任的第一道桥梁。然而,很多老板或者项目负责人在提到网站建设时,往往会有两种极端的想法:一种是觉得“不就…

2026/8/5 14:23:22 阅读更多 →
告别手动排列!Adobe Illustrator智能随机填充脚本Fillinger完全指南

告别手动排列!Adobe Illustrator智能随机填充脚本Fillinger完全指南

告别手动排列!Adobe Illustrator智能随机填充脚本Fillinger完全指南 【免费下载链接】illustrator-scripts Adobe Illustrator scripts 项目地址: https://gitcode.com/gh_mirrors/il/illustrator-scripts 还在为设计中的重复元素排列而烦恼吗?想…

2026/8/5 14:23:22 阅读更多 →
AI咨询服务如何收费?92%顾问踩过的5个定价陷阱及动态报价公式(附测算模板)

AI咨询服务如何收费?92%顾问踩过的5个定价陷阱及动态报价公式(附测算模板)

更多请点击: https://codechina.net 第一章:AI咨询服务如何收费?92%顾问踩过的5个定价陷阱及动态报价公式(附测算模板) AI咨询服务的定价远非简单按小时或项目打包计费,而是高度依赖客户成熟度、数据就绪度…

2026/8/5 14:23:22 阅读更多 →
nMigen开源生态:社区支持与贡献指南

nMigen开源生态:社区支持与贡献指南

nMigen开源生态:社区支持与贡献指南 【免费下载链接】nmigen A refreshed Python toolbox for building complex digital hardware. See https://gitlab.com/nmigen/nmigen 项目地址: https://gitcode.com/gh_mirrors/nmi/nmigen nMigen作为一款革新性的Pyth…

2026/8/5 14:23:22 阅读更多 →
零代码实战:用Teable开源电子表格快速搭建业务管理系统

零代码实战:用Teable开源电子表格快速搭建业务管理系统

零代码实战:用Teable开源电子表格快速搭建业务管理系统 【免费下载链接】teable ✨ AI Spreadsheet for Business 项目地址: https://gitcode.com/GitHub_Trending/te/teable 还在为数据管理而烦恼吗?想找一款既简单又强大的工具来管理团队工作&a…

2026/8/5 14:22:21 阅读更多 →

日新闻

Java缓存框架:JetCache

Java缓存框架:JetCache

TOC 一、简介 JetCache 是一个 Java 缓存抽象框架,为不同的缓存解决方案提供了统一的使用方式。 它提供的注解比 Spring Cache 更加强大。 JetCache 的注解支持原生 TTL、两级缓存以及在分布式环境中的自动刷新功能,同时你也可以通过代码直接操作 Cach…

2026/8/5 0:00:43 阅读更多 →
AD 铺铜设置十字连接,过孔全连接,新版AD的简单设置

AD 铺铜设置十字连接,过孔全连接,新版AD的简单设置

需求:通孔焊盘 十字花;过孔 Via 实心直连;贴片焊盘按需设置 AD 测试版本AD24 很多工程师踩坑:全部统一十字,导致接地过孔阻抗高、大电流发热! 一、快捷键打开规则 PCB 界面按下:D R 展开…

2026/8/5 0:00:43 阅读更多 →
AI素描转换技术深度拆解(2024最新论文+工业级落地代码):从Stable Diffusion ControlNet到LoRA微调全链路解析

AI素描转换技术深度拆解(2024最新论文+工业级落地代码):从Stable Diffusion ControlNet到LoRA微调全链路解析

更多请点击: https://kaifayun.com 第一章:AI生成素描效果 AI生成素描效果是计算机视觉与风格迁移技术融合的典型应用,其核心在于将彩色照片或RGB图像转换为具有手绘质感、明暗对比强烈、边缘清晰的单色素描图像。该过程通常依赖于深度学习模…

2026/8/5 0:00:43 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/4 13:24:41 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/5 13:13:56 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/5 10:20:36 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/4 13:38:24 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/4 11:09:16 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/4 13:38:40 阅读更多 →