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

news2025/6/5 22:21:33

        本章将会详细的介绍如何使用 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]);
    //然后需要启动定义好的 udp
    std::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 以及 port
            struct 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, 我都可以在我的服务器上看见对应的信息。

        

udp网络聊天室(最低级),也是一个 demo

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

        

                 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2398507.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

谷歌地图2022高清卫星地图手机版v10.38.2 安卓版 - 前端工具导航

谷歌地图2022高清卫星地图手机版是由谷歌公司推出的一款非常好用的手机地图服务软件&#xff0c;用户能够通过精准的导航和定位来查看地图&#xff0c;周边的商店等生活服务都会在地图上显示&#xff0c;用起来超级方便。 谷歌卫星高清地图 下载链接&#xff1a;夸克网盘分享 …

RAG的ETL Pipeline源码解读

原文链接&#xff1a;SpringAI(GA)&#xff1a;RAG下的ETL源码解读 教程说明 说明&#xff1a;本教程将采用2025年5月20日正式的GA版&#xff0c;给出如下内容 核心功能模块的快速上手教程核心功能模块的源码级解读Spring ai alibaba增强的快速上手教程 源码级解读 版本&a…

杭州白塔岭画室怎么样?和燕壹画室哪个好?

杭州作为全国美术艺考集训的核心区域&#xff0c;汇聚了众多实力强劲的画室&#xff0c;其中白塔岭画室和燕壹画室备受美术生关注。对于怀揣艺术梦想的考生而言&#xff0c;选择一所契合自身需求的画室&#xff0c;对未来的艺术之路影响深远。接下来&#xff0c;我们将从多个维…

晶台光耦在手机PD快充上的应用

光耦&#xff08;光电隔离器&#xff09;作为关键电子元件&#xff0c;在手机PD快充中扮演信号隔离与传输的“安全卫士”。其通过光信号实现电气隔离&#xff0c;保护手机电路免受高电压损害&#xff0c;同时支持实时信号反馈&#xff0c;优化充电效率。 晶台品牌推出KL817、KL…

【亲测有效 | Cursor Pro每月500次快速请求扩5倍】(Windows版)Cursor中集成interactive-feedback-mcp

前言&#xff1a;使用这个interactive-feedback-mcp组件可以根据用户反馈来决定是否结束这一次的请求。如果本次请求并没有解决我们的问题&#xff0c;那我们便可以选择继续这次请求流程&#xff0c;直到问题解决。这样的话&#xff0c;就可以避免为了修复bug而白白多出的请求。…

CRM管理软件的数据可视化功能使用技巧:让数据驱动决策

在当今数据驱动的商业环境中&#xff0c;CRM管理系统的数据可视化功能已成为企业优化客户管理、提升销售效率的核心工具。据企销客研究显示&#xff0c;具备优秀可视化能力的CRM系统&#xff0c;用户决策效率可提升47%。本文将深入解析如何通过数据可视化功能最大化CRM管理软件…

linux批量创建文件

文章目录 批量创建空文件touch命令批量创建空文件循环结构创建 创建含内容文件echo重定向多行内容写入 按日期创建日志文件根据文件中的列内容&#xff0c;创建文件一行只有一列内容一行有多列内容 批量创建空文件 touch命令批量创建空文件 # 创建文件file1.txt到file10.txt …

颠覆传统!单样本熵最小化如何重塑大语言模型训练范式?

颠覆传统&#xff01;单样本熵最小化如何重塑大语言模型训练范式&#xff1f; 大语言模型&#xff08;LLM&#xff09;的训练往往依赖大量标注数据与复杂奖励设计&#xff0c;但最新研究发现&#xff0c;仅用1条无标注数据和10步优化的熵最小化&#xff08;EM&#xff09;方法…

ssm学习笔记day04

RequestMapping 首先添加依赖 Maven的配置 测试 在controller创建HelloController&#xff0c;如果只加RequestMapping&#xff0c;默认跳转到新页面 如果要是加上ResponseBody就把数据封装在包(JSON)&#xff0c;标签RestController是前后分离的注解&#xff08;因为默认用…

Read View在MVCC里如何工作

Read View的结构 Read View中有四个重要的字段&#xff1a; m_ids&#xff1a;创建 Read View 时&#xff0c;数据库中启动但未提交的「活跃事务」的事务 id 列表 。min_trx_id&#xff1a;创建 Read View 时&#xff0c;「活跃事务」中事务 id 最小的值&#xff0c;即 m_ids …

建筑工程施工进度智能编排系统 (SCS-BIM)

建筑工程施工进度智能编排 (SCS-BIM) 源码可见于&#xff1a;https://github.com/Asionm/SCS-BIM 项目简介 本项目是一个面向建筑工程的施工进度智能编制平台&#xff0c;用户只需上传一份标准 IFC 建筑信息模型文件&#xff0c;系统将自动完成以下任务&#xff1a; 解析模…

pikachu通关教程-XSS

XSS XSS漏洞原理 XSS被称为跨站脚本攻击&#xff08;Cross Site Scripting&#xff09;&#xff0c;由于和层叠样式表&#xff08;Cascading Style Sheets&#xff0c;CSS&#xff09;重名&#xff0c;改为XSS。主要基于JavaScript语言进行恶意攻击&#xff0c;因为js非常灵活…

AIGC学习笔记(9)——AI大模型开发工程师

文章目录 AI大模型开发工程师008 LangChain之Chains模块1 Chain模块核心知识2 Chain模块代码实战LLMSequentialTransformationRouter AI大模型开发工程师 008 LangChain之Chains模块 1 Chain模块核心知识 组合常用的模块 LLM&#xff1a;最常见的链式操作类型SequentialChain…

Keil MDK5.37或更高版本不再预装ARM Compiler Version5导致编译错误的解决方法

Keil MDK5.37预装的是最新的ARM Compiler Version6 我们可以先右击查看工程属性 在Target标签下&#xff0c;我们可以看到Compiler Version5就是丢失的 在Target标签下&#xff0c;我们可以看到Compiler Version5就是丢失的 图1 以固件库方式编程&#xff0c;编译之后全是错…

Unity-UI组件详解

今天我们来学习Unity的UI的详解&#xff0c;这部分的内容相对较少&#xff0c;对于程序员来说主要的工作是负责将各种格式的图片呈现在显示器上并允许操作这些图片。 本篇帖子的理论依据依然是官方开源的UGUI代码&#xff0c;网址为&#xff1a;GitHub - Unity-Technologies/u…

黑马点评完整代码(RabbitMQ优化)+简历编写+面试重点 ⭐

简历上展示黑马点评 完整代码地址 项目描述 黑马点评项目是一个springboot开发的前后端分离项目&#xff0c;使用了redis集群、tomcat集群、MySQL集群提高服务性能。类似于大众点评&#xff0c;实现了短信登录、商户查询缓存、优惠卷秒杀、附近的商户、UV统计、用户签到、好…

Java 大视界 -- Java 大数据在智能安防视频监控中的异常事件快速响应与处理机制(273)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

【数据库】安全性

数据库安全性控制的常用方法&#xff1a;用户标识和鉴定、存取控制、视图、审计、数据加密。 1.用户标识与鉴别 用户标识与鉴别(Identification & Authentication)是系统提供的最外层安全保护措施。 2.存取控制 2.1自主存取控制(简称DAC) (1)同一用户对于不同的数据对…

【图像处理入门】4. 图像增强技术——对比度与亮度的魔法调节

摘要 图像增强是改善图像视觉效果的核心技术。本文将详解两种基础增强方法&#xff1a;通过直方图均衡化拉伸对比度&#xff0c;以及利用伽马校正调整非线性亮度。结合OpenCV代码实战&#xff0c;学会处理灰度图与彩色图的不同增强策略&#xff0c;理解为何彩色图像需在YUV空间…

HALCON 深度学习训练 3D 图像的几种方式优缺点

HALCON 深度学习训练 3D 图像的几种方式优缺点 ** 在计算机视觉和工业检测等领域&#xff0c;3D 图像数据的处理和分析变得越来越重要&#xff0c;HALCON 作为一款强大的机器视觉软件&#xff0c;提供了多种深度学习训练 3D 图像的方式。每种方式都有其独特的设计思路和应用场…