零基础学习计算机网络编程----socket实现UDP协议

article/2025/6/29 18:47:39

        本章将会详细的介绍如何使用 socket 实现 UDP 协议的传送数据。有了前面基础知识的铺垫。对于本章的理解将会变得简单。将会从基础的 Serve 的初始化,进阶到 Client 的初始化,以及 run。最后实现一个简陋的小型的网络聊天室。

        

目录

        1.UdpSever.h

       1.1 构造函数

       1.2 initServe 函数

         2. UdpSever.cc

        3. udpClient.hpp 

         3.1 构造函数

        3.2 init(初始化函数)

        3.3 run

      4. udpClient.cc

5. 对于  UdpSever.h 中run函数的实现

 6. 结尾


 

        1.UdpSever.h

            在这个文件里面需用定义 Sever 的一个类,里面变量为:_ip, _port,_sockfd。要实现的函数为构造函数、初始化(init)、运行(run)、析构函数。进行初始化是实现服务器的网络的核心,当然run 也非常重要。关于实现构造函数的时候为什么只需要 port 以及defaultip是什么我后面都会进行讲解。

class udpServer{public:udpServer(uint16_t port): _ip(defaultIp), _port(port){}void initServe(){}void start(){}~udpServer() {}private:uint16_t _port;string _ip;int _sockfd;};

       1.1 构造函数

        里面使用了 port,因为这个服务器的特点,我们使用的 linux 有2个,或是2个以上的 ip,因此我们在进行绑定的时候是不可以进行直接绑定的。要不然当使用不同的 ip 的时候,会导致数据无法从客户端发送到服务端。因此需要使用默认的ip = “0.0.0.0”。(后面的cc文件中使用智能指针的方式进行定义)

        1.2 initServe 函数

        进行初始化,本质就是使用 socket 打开文件,会返回文件描述符(可以理解为打开网卡这个文件,然后进行传递数据)。然后进行 bind ,使用 struct sockaddr_in loacl, 对于这个结构体里面的数据进行填写,然后进行 bind 绑定。

        对于soket 函数,官方的定义为:返回一个文件描述符fd, 第一个参数是选择网络通信还是本地通信,第二变量表示是使用udp 还是 tcp, 我们使用的是 sock_dgram(数据报的方式发送数据),第三个变量表示阻塞状态默认为 0;最后如何是返回 -1 进行退出操作。

 _sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (_sockfd == -1){cerr << "socket error" << errno << " : " << strerror(errno) << endl;exit(SOCKET_ERROR);}

        使用 bind 函数进行绑定。 需要文件的描述符,一个 sockaddr 的结构体,sizeof(sockaddr 的结构体)。关键就是在于处理这个 sockaddr 我们使用的 sockaddr_in 然后进行类型的转化。最后我们使用的是先进行清零,然后 第一个位置放上协议家族:AF_INET, 第二位置放上 port 端口号需要使用 htons(host主机到net网络当中为 short 的 16 位的方式), ip 直接使用 inet_addr(将点分十进制转化位 32 位的整形,然后变成网络当中的大端方式发送)。还需要注意的是由于 inet_addr 传递的字符串的指针,所以是使用 c_str。整体的代码如下。

 

void initServe(){// 使用 socket 函数,然后进行绑定_sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (_sockfd == -1){cerr << "socket error" << errno << " : " << strerror(errno) << endl;exit(SOCKET_ERROR);}// 进行band 绑定,注意是使用结构体进行绑定struct sockaddr_in local;bzero(&local, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(_port);local.sin_addr.s_addr = inet_addr(_ip.c_str());// 设置好 addr_in 就去进行绑定int n = bind(_sockfd, (struct sockaddr *)&local, sizeof(local));if (n == -1){cerr << "bind_error" << " : " << strerror(errno) << endl;exit(BIND_ERROR);}}

        对于启动函数,他本质就是一个无限的循环。 

for(;;)

         2. UdpSever.cc

        就。是在运行的时候,我们需要用户使用 ./ UdpSever port 如果不是就会提示如何使用。然后因为 argv[1] 使用的是字符串的方式,直接 atoi 就可以转化位整型。然后就是智能指针的定义,进行初始化,以及启动函数。

#include "udpServe.hpp"
#include <memory>
#include <unordered_map>using namespace djx;
static void Usage(std::string tmp)
{std::cout << "Usage:\n" << tmp << "local_port\n\n";
}
int main(int argc, char* argv[])
{if(argc != 2){//说明输入错误,需要重新输入Usage(argv[0]);exit(IN_ERROR);}uint16_t port = atoi(argv[1]);//然后需要启动定义好的 udpstd::unique_ptr<udpServer> usvr(new udpServer(port));usvr->initServe();usvr->start();return 0;
}

         最终实现的样式为这样,已经成功运行了。

        3. udpClient.hpp 

                跟udpSever是一样的都是4个函数,接下来我将会一一介绍。

         3.1 构造函数

                这个构造函数就需要告诉你,你要发送的服务器的ip地址,以及 port 端口号。 所以定义如下:

udpClient(uint16_t serveport, string serveip):_serveport(serveport),_serveip(serveip){}

        3.2 init(初始化函数)

                与udpSever一样都是使用socket,然后使用bind。但是这个bind 不要们进行显示的绑定,但是是需要进行绑定的。 为了保证独立性,ip 与 port 由操作系统为我们进行提供。

void initClient(){//click 是实现服务端的传送数据_sockfd = socket(AF_INET, SOCK_DGRAM, 0);if(_sockfd == -1){cerr << "socket error" << errno << " : " << strerror(errno) << endl;exit(2);}//进行绑定不要显示的进行绑定,是操作系统会帮助我们进行生成随机独立唯一的一个 port}

        3.3 run

        run就是运行函数,使用函数接口 sendto ,这个是一个输出型函数。是要将buf 缓冲里面的东西发送到 severip 和 severport 的 服务器当中,所以需要使用 sockaddr_in 对于里面的内容进行初始化。然后是对于 buffer 内容的输入。是使用 string message 类型的来进行存放数据。

 void run(){//需要使用函数 sendto, 但是在之前需要先获取到 secve 的ip 以及 portstruct sockaddr_in serve;serve.sin_family = AF_INET;serve.sin_port = htons(_serveport);serve.sin_addr.s_addr = inet_addr(_serveip.c_str());while(1){string message;cin >> message;sendto(_sockfd, message.c_str(), sizeof(message), 0, (struct sockaddr*)&serve, sizeof(serve));}}

      4. udpClient.cc

        与 Serve 类型都是先进行判断输入的argc 是为 3,如果是就进行启动。不是就告诉你如何使用。

#include "udpClient(fianll).hpp"
#include <memory>
using namespace std;
using namespace djx;
static void Usage(std::string tmp)
{cout << "Usage:\n\t" << tmp << " local_ip "<< "local_port\n\n";
}
int main(int argc, char* argv[])
{if(argc != 3){Usage(argv[0]);exit(1);}uint16_t port = atoi(argv[2]);string ip = argv[1];std::unique_ptr<udpClient> uclick(new udpClient(port, ip));uclick->initClient();uclick->run();return 0;
}

5. 对于  UdpSever.h 中run函数的实现

        start 函数需要接受从客服端发来的信息,通过之前启动的 sokce 以及 bind,启动了 udp 协议。内核就会帮助我们对于定义的 struct scokaddr_in 进行内容的填充(来自客户端发送过来的数据)。里面需要的函数为 recvfrom 这是一个输入输出型参数。从  struct scokaddr_in 获取输入参数,将参数输出到 buffer 这个缓存当中,然后进行打印。

        整体的实现如下,其中 full 定义为 1024 个整形。然后 s 表示的是buffer 里面读取到的个数,如果是小于0,就表示没有数据,直接结束此次循环。为了照顾计算机网络的数据严格传送的特点,len 的长度需要定义为 socklen_t 。使用 char 的时候写入的大小是从 0 开始的,所以是要sizeof -  1.

void start(){char buffer[full]; for (;;){// 用来存放 哪个click发送来的数据struct sockaddr_in peer;socklen_t len = sizeof(peer); // 为了照顾vecvfrom函数,所以使用这个socken_t;ssize_t s = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len);if (s > 0){buffer[s] = 0; string message = buffer;    // s表示获取到的长度string click_ip = inet_ntoa(peer.sin_addr); // 直接就是从结构体变过来int click_port = ntohs(peer.sin_port);cout << click_ip << "[" << click_port << "]#" << message << endl;}}}

 6. 结尾

        到此 udp 简单实现已经结束了,还不是很全面因为我们是要得到数据,然后实现相应的工作,这里还没有实现功能,就是实现了一个简陋的网络聊天室。任意一台主机通过输入./udpClient ip + port, 我都可以在我的服务器上看见对应的信息。

        以上是对于计算网络中基础知识的了解,这个文章用于我的学习记录,如果是有其他的错误还请批评指正。如果对你有帮助还请给我点个赞👍👍👍。     

        

                 


http://www.hkcw.cn/article/DTeECatZTs.shtml

相关文章

深入了解linux系统—— 进程间通信之管道

前言 本篇博客所涉及到的代码一同步到本人gitee&#xff1a;testfifo 迟来的grown/linux - 码云 - 开源中国 一、进程间通信 什么是进程间通信 在之前的学习中&#xff0c;我们了解到了进程具有独立性&#xff0c;就算是父子进程&#xff0c;在修改数据时也会进行写时拷贝&…

电脑使用VPN后直接关机,再次打开后无法上网的问题

出现这种问题&#xff0c;都是在使用VPN后&#xff0c;以前自己都是通过杀毒软件的网络修复工具进行解决的。 但现在有了一个更简单的方法&#xff1a; 打开设置&#xff0c;找到网络中的代理,然后关闭即可。

【Linux】线程控制

&#x1f4dd;前言&#xff1a; 这篇文章我们来讲讲Linux——线程控制 &#x1f3ac;个人简介&#xff1a;努力学习ing &#x1f4cb;个人专栏&#xff1a;Linux &#x1f380;CSDN主页 愚润求学 &#x1f304;其他专栏&#xff1a;C学习笔记&#xff0c;C语言入门基础&#xf…

CppCon 2014 学习:Hardening Your Code

“Hardening Your Code” 是指增强代码的健壮性、安全性、可维护性和可测试性&#xff0c;确保在各种边界条件、错误场景甚至恶意输入下&#xff0c;代码依然稳定运行&#xff0c;不崩溃、不泄露资源&#xff0c;也不产生未定义行为。 什么是“Hardening Your Code”&#xff…

【js逆向_AES】某专业技术人员继续教育平台登录分析及模拟实践

目标&#xff1a;account&#xff0c;password加密 网址&#xff1a;aHR0cHM6Ly93d3cuZ3N6eGp5cHguY24vd2ViL2luZGV4 请求载荷加密方式 账号加密&#xff1a; 网页调试输出&#xff1a; python代码&#xff1a; from Cryptodome.Cipher import AES import base64 from Crypto…

《信号与系统》--期末总结V1.0

《信号与系统》–期末总结V1.0 学习链接 入门&#xff1a;【拯救期末】期末必备&#xff01;8小时速成信号与系统&#xff01;【拯救期末】期末必备&#xff01;8小时速成信号与系统&#xff01;_哔哩哔哩_bilibili 精通&#xff1a;2022浙江大学信号与系统&#xff08;含配…

可视化大屏通用模板Axure原型设计案例

本文将介绍一款基于Axure设计的可视化大屏通用模板&#xff0c;适用于城市、网络安全、园区、交通、社区、工业、医疗、能源等多个领域。 模板概述 这款Axure可视化大屏通用模板集成了多种数据展示模块和组件&#xff0c;旨在为用户提供一个灵活、可定制的数据展示平台。无论…

AI来敲门:我们该如何与焦虑共舞

最近一份覆盖国内上万职场人的调研报告像一颗深水炸弹&#xff0c;在职场圈激起层层涟漪——85.53%的人担心AI会抢走自己的饭碗&#xff0c;67.57%的人认为这会在五年内发生。更令人意外的是&#xff0c;这些焦虑的职场人中&#xff0c;高达34.13%出现了抑郁症状&#xff0c;这…

单调栈(打卡)

本篇基于b站灵茶山艾府。 下面是灵神上课讲解的题目与课后作业&#xff0c;课后作业还有三道实在写不下去了&#xff0c;下次再写。 739. 每日温度 给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是…

【C语言入门级教学】冒泡排序和指针数组

文章目录 1.冒泡排序2.⼆级指针3.指针数组4.指针数组模拟⼆维数组 1.冒泡排序 冒泡排序的核⼼思想&#xff1a;两两相邻的元素进⾏⽐较。 //⽅法1 void bubble_sort(int arr[], int sz)//参数接收数组元素个数 { int i 0;for(i0; i-1; i) { int j 0; for(j0; j-1; j) { …

源码解析(三):Stable Diffusion

原文 技术博客 &#x1f600; Stable Diffusion是一种基于扩散模型&#xff08;Diffusion Model&#xff09;的生成式AI技术&#xff0c;通过逐步去噪过程将随机噪声转化为高质量图像。其核心优势在于开源免费、支持本地部署&#xff0c;且能通过文本提示&#xff08;prompt&am…

洛雪音乐+多种音源同步更新,附带安装教程 -【PC端/安卓端】音乐软件

今天&#xff0c;就为大家介绍一款全网免费听歌神器——‌洛雪音乐‌&#xff01; &#x1f3b6; 洛雪音乐&#xff1a;&#xff08;文末获取软件&#xff09; 一、软件亮点 全平台支持‌&#xff1a;无论是Windows系统还是安卓手机&#xff0c;洛雪音乐都能随时伴你左右&am…

【CATIA的二次开发18】根对象Application涉及用户交互相关方法

在CATIA VBA开发中&#xff0c;对根对象Application涉及用户交互相关方法进行详细总结&#xff0c;并且用不同形式展示出来。供大家后续开发全面了解Application对象的方法&#xff0c;以便在开发过程中快速查找和使用&#xff1a; 一、Application常用方法分类 1、基础控制与…

密码学:解析Feistel网络结构及实现代码

概述 Feistel网络是由IBM密码学家Horst Feistel在20世纪70年代提出的对称加密结构&#xff0c;已成为现代分组密码的核心框架。DES、Blowfish、RC5等经典加密算法均基于此结构。其核心思想是将输入明文分组分成左右两半&#xff0c;通过多轮迭代操作实现加密&#xff0c;每轮使…

JavaSE知识总结(集合篇) ~个人笔记以及不断思考~持续更新

目录 集合 List List的各种接口API List的五种遍历方式 List的删除是内部是怎么做的&#xff1f; ArrayList和LinkedList的区别 Vetor和Stack是什么&#xff1f; Set Set的特点 HashSet TreeSet LinkedHashSet Map HashMap LinkedHashMap TreeMap 集合 在Java…

Linux中的mysql备份与恢复

一、安装mysql社区服务 二、数据库的介绍 三、备份类型和备份工具 一、安装mysql社区服务 这是小编自己写的&#xff0c;没有安装的去看看 Linux换源以及yum安装nginx和mysql-CSDN博客 二、数据库的介绍 2.1 数据库的组成 数据库是一堆物理文件的集合&#xff0c;主要包括…

也说字母L:柔软的长舌

英语单词 tongue&#xff0c;意为“舌头” tongue n.舌&#xff0c;舌头&#xff1b;语言 很显然&#xff0c;“语言”是引申义&#xff0c;因为语言是抽象的&#xff0c;但舌头是具象的&#xff0c;根据由简入繁的原则&#xff0c;tongue显然首先是象形起义&#xff0c;表达…

【机器学习】决策树

目录 一、引言 二、决策树的构造 三、决策树的ID3算法 四、决策树的C4.5算法 五、决策树的CART算法 六、动手实现决策树C4.5的算法详解步骤以及Python完整代码实现 一、引言 在机器学习中,有一种与神经网络并行的非参数化模型——决策树模型及其变种。顾名思义,决…

美提高钢铝关税至50% 欧盟深表遗憾 谈判进程加速

6月2日,欧盟委员会新闻发言人对美国宣布将钢铁和铝关税从25%提高至50%表示遗憾,认为这一决定加剧了大西洋两岸的经济不确定性。发言人提到谈判仍在继续,双方已同意加快谈判进程,并计划本周举行会谈。欧盟贸易专员塞夫科维奇将于6月4日在法国巴黎会见美国贸易代表格里尔。美…

基于ubuntu和树莓派环境对游戏进行移植

目录 一、在Ubuntu中对波斯王子游戏进行移植 1.1修改Ubuntu系统的仓库镜像网站为国内网站 1.2安装mininim 软件所依赖的库 1.3 编译mininim 软件 二、在树莓派中对波斯王子游戏移植 2.1安装相关环境 2.3编译mininim 软件 三、使用树莓派实现流水灯 一、在Ubuntu中对波…