网络与通信程序设计-基于UDP的广播通信实例

news2025/7/15 9:45:54

目录

实验内容和设计思想

实验的内容

UDP的设计思想

UDP的协议头部

UDP通信编程思想

UDP的工作流程

UDP编程收发函数

广播通信

广播模式设置

广播套接字

UDP Socket的使用过程

UDP广播通信实例实现

initsock.h

服务器发送广播消息

客户端接收广播消息

运行效果

实验心得 


实验内容和设计思想

通过本文的学习,希望可以帮助大家完成一个简易的基于UDP的广播通信实例

实验的内容

编写基于广播通信模型的服务器端和客户端通信程序,要求编程实现服务器端与客户端之间广播数据传递。服务器端向所有客户端发送今天是个好日子!”广播消息,客户端收到并在本地显示给用户。

UDP的设计思想

由于UDP协议本身异常简单,实际上只为IP传输起到了桥梁的作用,在一些场景上通过【 应用层->UDP->IP 】的封装方式,可以极大的提高程序调用效率。

UDP(User Datagram Protocol)传输与IP传输非常类似。你可以将UDP协议看作IP协议暴露在传输层的一个接口。UDP协议同样以数据包(datagram)的方式传输,它的传输方式也是"Best Effort"的,所以UDP协议也是不可靠的(unreliable)。

UDP是一个无连接协议,传输数据之前源端和终端不建立连接,当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。在发送端,UDP传送数据的速度仅仅是受应用程序生成数据的速度、计算机的能力和传输带宽的限制;在接收端,UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段。

由于传输数据不建立连接,因此也就不需要维护连接状态,包括收发状态等,因此一台服务机可同时向多个客户机传输相同的消息。

UDP的协议头部

source port出发端口
destination port目的地端口
LengthUDP包的长度
ChecksumIP协议的header checksum算法相类似


UDP通信编程思想

UDP的工作流程

UDP 用户数据报协议提供的是无连接的、不可靠的数据传输服务,但是不需要像 TCP 那样建立连接,所以传输效率高。

 

 对比TCP的工作流程

UDP编程收发函数

UDP编程的数据收发函数为sendto()和recvfrom()

int sendto(
    SOCKET s,                            //发送数据的套接字
    const char FAR * buf,                //发送数据的缓冲区
    int len,                             //发送数据的长度
    int flags,                           //一般指定为0
    const struct sockaddr FAR * to,      //指向一个包含目标地址和端口号的sockaddr_in结构
    int tolen                            //为sockaddr_in结构的大小
    );

同样的接收数据的函数是 recvfrom(),UDP接收数据时也需要知道通信对端的地址信息。

int recvfrom(SOCKET s,char FAR*buf,int len,int flag,struct sockaddr_in FAR*from,int FAR*fromlen)

广播通信

利用广播(broadcast)可以将数据发送给本地子网上的每个机器,同时需要有一些线程在机器上监听到来的数据。广播的缺点是如果多个进程都发送广播数据,网络就会阻塞,网络性能便会受到影响。

利用广播(broadcast)可以将数据发送给本地子网上的每个机器。

广播模式设置

广播套接字

获取和设置套接字选项的函数分别是 getsockopt() 和 setsockopt(),函数调用出错时返回 SOCKET ERROR。

int setsockopt(
    SOCKET s,
    int level,
    int optname,
    const char FAR * optval,
    int* optlen
    );

参数说明:

 

同理接收套接字也采用类似于setsockopt的定义模式

int getsockopt(SOCKET s,int level, optname, const char FAR * optval,int* optlen);

此外,进行广播通信,必须打开广播选项SO_BROADCAST为True。

SOBROADCAST 选项设置套接字传输和接收广播消息,如果给定套接字已经被设置为接收或者发送广播数据,查询此套接字选项将返回TRUE,此选项对于那些不是SOCK_STREAM类型的套接字有效。

 SOCKET s = ::socket(AF_INET, SOCK_DGRAM, 0);
    // 有效SO_BROADCAST选项
    BOOL bBroadcast = TRUE;
    ::setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char*)&bBroadcast, sizeof(BOOL));

UDP Socket的使用过程

1. 初始化网络库

2. 创建SOCK_DGRAM类型的Socket。

3. 绑定套接字。

4. 发送、接收数据。

5. 销毁套接字。

6. 释放网络库。


UDP广播通信实例实现

实现服务器端与客户端之间广播数据传递,服务器端向所有客户端发送“今天是个好日子!”广播消息,客户端收到并在本地显示。

initsock.h

#include <winsock2.h>
#pragma comment(lib, "WS2_32")  // 链接到 WS2_32.lib

class CInitSock
{
public:
    /*CInitSock 的构造器*/
    CInitSock(BYTE minorVer = 2, BYTE majorVer = 2)
    {
        // 初始化WS2_32.dll
        WSADATA wsaData;
        WORD sockVersion = MAKEWORD(minorVer, majorVer);
        if (::WSAStartup(sockVersion, &wsaData) != 0)
        {
            exit(0);
        }
    }

    /*CInitSock 的析构器*/
    ~CInitSock()
    {
        ::WSACleanup();
    }
};

服务器发送广播消息

对于 UDP 来说存在一个特定的广播地址 255.255.255.255,广播数据都应该发送到这里。发送方程序在创建套接字后使用 setsockopt 函数打开 SO_BROADCAST选项,然后设置广播地址 255.255.255.255,使用 sendto 函数向端口号 54321 不断发送广播数据。

#include "initsock.h"
#include <iostream>
#include <windows.h>
using namespace std;

CInitSock theSock;

int main()
{
    SOCKET s = ::socket(AF_INET, SOCK_DGRAM, 0);
    // 有效SO_BROADCAST选项
    BOOL bBroadcast = TRUE;
    ::setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char*)&bBroadcast, sizeof(BOOL));

    // 设置广播地址和广播端口号
    SOCKADDR_IN bcast;
    bcast.sin_family = AF_INET;
    bcast.sin_port = htons(54321);
    bcast.sin_addr.s_addr = INADDR_BROADCAST;

    // 发送广播
    cout << "  开始向端口发送广播数据... \n" << endl;
    char sz[] = "今天是个好日子! \r\n";
    while (TRUE)
    {
        time_t now = time(0);    // 基于当前系统的当前日期/时间
        char* dt = ctime(&now);
        ::sendto(s, sz, strlen(sz), 0, (sockaddr*)&bcast, sizeof(bcast));
        cout << dt << "发送广播:" << sz << endl;
        ::Sleep(5000);
    }
    return 0;
}

客户端接收广播消息

使用 recvfrom 函数,向端口号 54321 接收广播数据。

#include "initsock.h"
#include <iostream>
#include <windows.h>
using namespace std;

CInitSock theSock;

int main()
{
    SOCKET s = ::socket(AF_INET, SOCK_DGRAM, 0);

    // 首先要绑定一个本地地址,指明广播端口号
    SOCKADDR_IN sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(54321);
    sin.sin_addr.S_un.S_addr = INADDR_ANY;
    if (::bind(s, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR)
    {
        cout << " bind() failed!" << endl;
        return 0;
    }

    // 接收广播
    cout << "  开始在端口接收广播数据... \n" << endl;
    SOCKADDR_IN addrRemote;
    int nLen = sizeof(addrRemote);
    char sz[256];
    while (TRUE)
    {
        int nRet = ::recvfrom(s, sz, 256, 0, (sockaddr*)&addrRemote, &nLen);
        if (nRet > 0)
        {
            sz[nRet] = '\0';
            time_t now = time(0);    // 基于当前系统的当前日期/时间
            char* dt = ctime(&now);
            cout << dt << "接收到广播:" << sz << endl;
        }
    }
    return 0;
}

运行效果

实验心得 

1,为了进行广播通信,必须打开广播选项SO_BROADCAST

2,接收方一定要知道广播方的端口号,然后绑定此端口号才能正确接收。

3,UDP(User Datagram Protocol)传输与IP传输非常类似。你可以将UDP协议看作IP协议暴露在传输层的一个接口。UDP协议同样以数据包(datagram)的方式传输,它的传输方式也是"Best Effort"的,所以UDP协议也是不可靠的(unreliable)。

4,由于UDP协议本身异常简单,实际上只为IP传输起到了桥梁的作用,在一些场景上通过应用层->UDP->IP的封装方式,可以极大的提高程序调用效率。

5,UDP是一个无连接协议,传输数据之前源端和终端不建立连接,当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。在发送端,UDP传送数据的速度仅仅是受应用程序生成数据的速度、计算机的能力和传输带宽的限制;在接收端,UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段。

由于传输数据不建立连接,因此也就不需要维护连接状态,包括收发状态等,因此一台服务机可同时向多个客户机传输相同的消息。

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

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

相关文章

HttpMessageConverter 消息转换器

HttpMessageConverter 简介 HttpMessageConverter 是SpringMVC中提供的一个策略接口&#xff0c;它是一个消息转换器类&#xff0c;Spring Mvc中就是由HttpMessageConverter负责转换HTTP的请求和响应。 默认情况下&#xff0c;Spring Boot 会自动加载如下消息类型转换器&…

spring复习01,IOC的思想和第一个spring程序helloWorld

spring复习01&#xff0c;IOC的思想及本质IOC的思想一个小例子&#xff0c;来体会IOC的基础思想。dao层dao层接口dao层实现类service层service层接口service层实现类测试代码service层实现类修改测试代码修改IOC容器在spring中的简单实现创建项目在pom.xml中引入依赖实体类创建…

C# 拨号面板 高亮显示

一 拨号面板 显示&#xff1a;绘制4x3; 数据&#xff1a;每一格对应一个数字&#xff1b; 行为&#xff1a;点击单元格时有反应&#xff1b; 二 拨号事件 当点击某个号码时&#xff0c;触发拨号事件。 设计思路&#xff1a; ① 重写OnMouseClick(); ② 根据鼠标点击位置&am…

JVET-AB0117-基于模板的帧内推导的方向性融合

本提案是针对 ECM 中的 TIMD&#xff08;基于模板的帧内模式推导&#xff0c;Template based intra mode derivation &#xff09; 的技术的加权方式的改进。具体地&#xff0c;本提案提出使用方向混合&#xff08;directional blending&#xff09;来加权TIMD使用模板推导的两…

SpringBoot SpringBoot 原理篇 1 自动配置 1.13 bean 依赖属性配置

SpringBoot 【黑马程序员SpringBoot2全套视频教程&#xff0c;springboot零基础到项目实战&#xff08;spring boot2完整版&#xff09;】 SpringBoot 原理篇 文章目录SpringBootSpringBoot 原理篇1 自动配置1.13 bean 依赖属性配置1.13.1 环境准备1.13.2 bean 依赖属性配置1…

【软件测试】作为测试人,因工作与开发吵了一架碰撞,该咋办......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 测试与开发在工作中…

【网页设计】HTML+CSS保护野生动物北极熊介绍网页设计专题

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

傻白入门芯片设计,RDL/Interposer/EMIB/TSV(五)

一、再分配层&#xff08;RDL&#xff09; 主要原理就是在晶片表面沉积金属层和介电层。它形成了一个再分配层&#xff0c;以携带相应的金属布线模式&#xff0c;并在芯片外的松散区域上重新排列芯片的IO端口。由于RDL形成的金属布线的线宽和间距较小&#xff0c;从而提供了更…

MySQL之InnoDB架构浅析

InnoDB是一个兼顾高可靠性和高性能的通用存储引擎。在 MySQL 5.7 中&#xff0c;InnoDB是默认的 MySQL 存储引擎。 InnoDB 的主要优势 支持事物&#xff0c;具备crash-safe的能力支持行锁以及MVCC&#xff0c;具备良好的多用户并发性和性能Buffer Pool&#xff0c;提升热点数…

第8章 综合案例—构建DVD租赁商店数据仓库

目录 章节概要 案例背景介绍 数据仓库的架构模型 数据仓库的架构模型 数据库sakila的下载和安装 数据库sakila简介 数据库sakila中 数据表之间的关系 数据表简介 用于储存电影基本信息及相关介绍的数据&#xff0c;该数据表各个字段的含义如表。 用于储存定义电影id所…

Python爬虫

前言 这个故事&#xff0c;从头讲起。 2022 年上班第一天&#xff0c;我们做了一个重要决定&#xff0c;就是打造精品学习路线&#xff0c;为初学者指明前进的方向&#xff0c;以及常见的避坑技巧。 &#xff08;文末送读者福利&#xff09; 我承认这是一件非常有挑战的事情…

自动驾驶感知算法实战6——目标分类详解(ResNet、VGG、GoogLeNet等)

自动驾驶感知算法实战专栏:https://blog.csdn.net/charmve/category_12097938.html目录 1 网络分类2 详解 ResNet3 详解 VGG4 稠密连接网络(DenseNet)5 详解 GoogLeNet6 详解 Fast R-CNN1 网络分类 来自:https://charmve.github.io/computer-vision-in-action/#/book_prefa…

构建房地产行业智慧采购新模式,采购协同商城系统护航企业采购数字化转型

采购是房地产企业控制成本的龙头&#xff0c;同时还直接影响着工程质量。随着采购工作推进的不断深化&#xff0c;对地产物资采购精细化管理的要求也在日益加强&#xff0c;如何做好采购工作成为房地产企业实现数字化转型升级进程必须突破的壁垒。 房地产作为一个资源整合性行…

排序算法及java实现

简介 排序算是非常基础的算法&#xff0c;为什么我们需要排序算法呢&#xff1f;假设我们只有10个数&#xff0c;或者100个数&#xff0c;其实根本不需要研究这么多的排序算法&#xff0c;正常我们会使用的插入排序或者选择排序足够了&#xff0c;没必要发明快排&#xff0c;基…

第九章 哈希表 AcWing 2 1549. 集合相似度

第九章 哈希表 AcWing 2 1549. 集合相似度 原题链接 AcWing 1549. 集合相似度 算法标签 哈希表 位运算 思路 使用unordered_set数据结构将数据插入指定集合 如何计算Nc&#xff08;两集合交集&#xff09; 如何计算Nt&#xff08;两集合并集&#xff09; 输出问题 WA 精…

干掉 “重复代码”,这三种方式绝了!

软件工程师和码农最大的区别就是平时写代码时习惯问题&#xff0c;码农很喜欢写重复代码而软件工程师会利用各种技巧去干掉重复的冗余代码。 业务同学抱怨业务开发没有技术含量&#xff0c;用不到设计模式、Java 高级特性、OOP&#xff0c;平时写代码都在堆 CRUD&#xff0c;个…

BCD编码和ASCII码

计算机里&#xff0c;字母&#xff0c;各种字符以及指挥计算机执行操作的指令&#xff0c;均用二进制数的组合表示&#xff0c;称为二进制编码 目录 ASCII码&#xff08;汇编语言程序设计的时候会常用&#xff09; BCD码&#xff08;了解&#xff09; ASCII码&#xff08;汇…

等数值计算方法学习笔记第4章第三部分【数值积分(数值微分)】

高等数值计算方法学习笔记第4章第三部分【数值积分&#xff08;数值微分&#xff09;】六、数值微分&#xff08;第四次课&#xff09;1、中点方法与误差分析2、插值型的求导公式3、习题和表格4、知识结构图六、数值微分&#xff08;第四次课&#xff09; 1、中点方法与误差分析…

【图像处理】小波编码图像中伪影和纹理的检测(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

一年一度的科技狂欢盛会——2022亚马逊云科技re:Invent全球大会

一年一度的科技狂欢盛会&#xff0c;2022年亚马逊云科技re:Invent全球大会即将于北京时间2022年11月29日盛大开启&#xff01;届时全球各领域关注“云计算圈”发展的人都将齐聚一堂&#xff0c;共同聆听5大重磅嘉宾的主题演讲&#xff0c;700前沿技术话题…… 携全球合作伙伴&…