系统编程-UDP

news2024/11/15 15:59:06

UDP

目录

UDP

引入

使用 UDP 的注意事项

一、单播的流程 -- 一对一

如何实现端口和地址重复绑定

二、广播的流程 -- 一对多

三、组播的流程 -- 多对多

加入组播,需要使用 setsockopt 函数

主要代码 -- 主要是发送方


引入

-- UDP协议的特点

  • 无连接性: UDP是无连接的协议,这意味着通信的双方不需要在通信之前建立连接。每个UDP数据报都是独立的,它们可以单独发送,没有依赖关系。

  • 不可靠性: UDP不提供数据传输的可靠性保证。它不会像TCP那样提供重传、确认和流量控制等机制。这意味着如果发送的数据丢失或者损坏,UDP不会自动重新发送,需要应用层自行处理。

  • 速度和低延迟: 由于没有连接状态维护和复杂的确认机制,UDP的开销比TCP小,因此在速度和延迟方面表现更好。这使得它适用于实时应用,如语音通话和在线游戏。

  • 数据报格式: UDP数据报包含了目标端口号和源端口号,这些信息用于将数据传递给正确的应用程序。但是,数据报本身没有保证按顺序到达或完整到达。

  • 无拥塞控制: UDP不具备TCP的拥塞控制机制,因此在网络拥塞的情况下,UDP数据报可能会丢失或延迟增加。

  • 广播和多播支持: UDP支持向特定组中的多个主机发送数据,这称为多播(Multicast)。也可以将数据报广播到网络中的所有主机,这称为广播(Broadcast)。

  • 适用场景: UDP适用于需要快速传输和实时性要求较高的应用,如语音和视频流、在线游戏、实时传感数据等。它不适用于需要可靠传输和数据完整性的场景,因为这些方面没有被UDP提供。

一对一 单播
一对多 广播
多对多 组播
在 UDP 中没有客户端和服务器之分
只有发送方和接收方

使用 UDP 的注意事项

-- 1 使用 udp 通信时 创建的套接字时用的参数与 tcp 不同

int socket(int domain, int type, int protocol) domain:AF_INET
type:SOCK_DGRAM -- 表示使用UDP
protocol:0
成功返回 udp 通信套节字
失败返回 -1

-- 2 udp 没有连接过程 所以没有服务器端和客户端

只有发送方和接收方
发送方需要不需要接收方的 ip 和 port?
100%要知道
所以接收方需要进行绑定操作将 ip 和 port 绑定到套接字上

-- 3 数据的发送和接收函数变了

#include <sys/types.h>
#include <sys/socket.h>
-- 发送函数
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen) 函数前四个参数跟 send 函数一模一样
后面两个参数需要填写接收方的 ip 和 port
dest_addr:填写接收方的 ip 和 port

-- 接收函数
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen)

-- 函数的参数:

  • src_addr:用来保存发送方的 ip 和 port
  • addrlen:填写一个保存了第二个参数结构体大小的变量的地址

一、单播的流程         -- 一对一

alt text

-- 接收方:

  • 1、创建通信套接字
    socket(AF_INET,SOCK_DGRAM,0)
  • 2、 bind 自己的 ip 和 port
    方便发送方 发送数据

-- 注:不进行bind操纵,套接字也会有ip和端口,但是是随机分配的,所以发送方无法发送数据,所以bind的主要作用是分配一个指定的ip和端口。

  • 3、 接收方 recvfrom 就可以了
    (1) char *inet_ntoa(struct in_addr in)
    接收方保存了发送的 ip 可以通过这个函数转化成点分十进制
    (2) uint16_t ntohs(uint16_t netshort)
    将大端的端口转化为小端

-- 发送方

  • 1、创建套节字
  • 2、直接发送至指定的 ip 和 port

-- 注:udp只管发送,那么他怎么知道发送给谁呢?
send_to函数有接受方的ip和port,接收方bind了ip和port,所以发送方和接收方就建立了联系。

如何实现端口和地址重复绑定

-- 在程序中写下如下代码即可

int opt = 1;
// sockfd 为需要端口复用的套接字
setsockopt(要复用的套接字, SOL_SOCKET, SO_REUSEADDR|SO_REUSEPORT, (const void *)&opt, sizeof(opt));

二、广播的流程 -- 一对多

alt text

-- 广播:特殊的地址:网络号.255

  • 例如:广播地址是192.168.110.255,其中主机号部分(最后一个八位字节)全部为255,表示网络中的所有主机。

-- 广播的地址是特定的

  • 在终端输入ifconfig,broadcast 后面就是广播地址

alt text

你向这个广播地址发送的消息会被转发到当前局域网的所有主机下
如向192.168.110.255 这个 IP 发送消息
192.168.110.0~192.168.110.254 这些 IP 都会收到消息
所有的 192.168.110.xxx 的地址都会收到消息

  • sento 中发送的端口 和 自身接受的端口 必须一样
    前提必须是同一个端口 port
    接收广播的套节字的端口必须跟发送至广播的端口一致

-- 要想使用广播必须要先激活广播

  • 使用 setsockopt 函数进行激活广播权限

  • int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen)

这个函数较为复杂
根据 level 的不同选项 optname 也会有不同的选项
level:选择 SOL_SOCKET
那么optname就选择SO_BROADCAST
optval:int 类型
optlen:sizeof(int)

-- 下面是激活广播的代码 直接粘贴复制使用即可

1、在广播的发送方添加以下代码,表示端口可以复用,激活广播权限

int opt = 1;
// sockfd 为需要端口复用的套接字
setsockopt(socket, SO_BROADCAST,&opt,sizeof(opt));

2、广播的接收方绑定的地址必须为 INADDR_ANY

struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;  //表示用的是IPV4的地址
addr.sin_port = htons(PORT);//这里的PORT是共定义
addr.sin_addr.s_addr = INADDR_ANY; // 绑定地址必须为 INADDR_ANY

三、组播的流程 -- 多对多

alt text

-- 只有加入组播的套节字才可以进行接收
多播(组播)

  • 发送方需要加入一个特定的 ip 地址来实现组播,给这个组的IP和端口发送信息,会转发给所有在这个组播中的套接字

  • 接受方需要加入组播的组ip才能接收到信息

  • !!!这里发送方要发送ip和接收方要加入的组ip是一致的

  • 组播地址:D类地址

组播的 IP 地址:
224.0.0.0~224.0.0.255 为预留的组播地址(永久组地址),地址 224.0.0.0 保留不做分配,其它地址供路由
-- 协议使用 224.0.1.0~224.0.1.255 是公用组播地址,可以用于 Internet
224.0.2.0~238.255.255.255 为用户可用的组播地址(临时组地址),全网范围内有效 -- 我们可以用的地址
239.0.0.0~239.255.255.255 为本地管理组播地址,仅在特定的本地范围内有效

加入组播,需要使用 setsockopt 函数

-- 函数头文件

  • #include <sys/types.h>
  • #include <sys/socket.h>

-- 函数原型

  • int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

-- 函数的参数

  • sockfd:套接字
  • level:选项的级别

IPPROTO_IP         -- IP 级别         -- 组播使用

  • optname:选项的名称

level 为 IPPROTO_IP
optname选IP_ADD_MEMBERSHIP         在指定接口上加入组播组

  • optval:当 optname 为 IP_ADD_MEMBERSHIP

optval 为该结构体

-- 结构体

struct ip_mreqn {       
struct in_addr imr_multiaddr; /* 多播组的地址 */
struct in_addr imr_address;
/* 本地的 IP 地址 */
int
imr_ifindex;
/* 接口索引 0 表示任意接口 */
};
imr_ifindex= ifnametoindex(“ens33”);
  • optlen:optval 的大小

  • 多播流程:
    1 创建 udp 套接字
    2 如果要接受多播的消息 需要加多播组 ,以下结构体为加入组播的代码

struct ip_mreqn addr = {0};
addr.imr_address.s_addr = INADDR_ANY;
addr.imr_multiaddr.s_addr = inet_addr("224.224.224.224");
setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&addr,sizeof(addr));

3 绑定自身的 ip 和 port
        port 需要跟多播的端口一样
4 recvfrom
        如果要向多播组发送消息 直接 sendto 多播的 ip 和 port 就可以了

alt text

主要代码 -- 主要是发送方

  • 单播发送方
char buff[30]={0};
    int num = 0;

    struct sockaddr_in R_addr = {0};
    R_addr.sin_family = AF_INET;
    R_addr.sin_port = htons(PORT);//发送的端口
    R_addr.sin_addr.s_addr = inet_addr(IP);//发送的 IP

    while(1)
    {
        sprintf(buff,"num:%d",num++);
        sendto(fd,buff,sizeof(buff),0,(struct sockaddr *)&R_addr,sizeof(R_addr));
        perror("sendto()");
        sleep(1);

    }
    
  • 单播接收方
struct sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);
    addr.sin_addr.s_addr = inet_addr(IP);
    bind(fd, (struct sockaddr*)&addr,sizeof(addr));

    char buff[50]={0};
    struct sockaddr_in S_addr = {0};
    int len = sizeof(S_addr);

    while(1)
    {
        recvfrom(fd,buff,sizeof(buff),0,(struct sockaddr*)&S_addr,
        &len);
        printf("IP:%s\n",inet_ntoa(S_addr.sin_addr));
        //将大端转化为小端
        printf("PORT:%d\n",ntohs(S_addr.sin_port));
        printf("接收到:%s\n",buff);
    }
  • 广播发送方
char buff[30]={0};
    int num = 0;

    int opt = 1;
    setsockopt(fd,SOL_SOCKET,SO_BROADCAST,&opt,sizeof(opt));

    struct sockaddr_in R_addr = {0};
    R_addr.sin_family = AF_INET;
    R_addr.sin_port = htons(PORT);//发送的端口
    R_addr.sin_addr.s_addr = inet_addr(IP);//发送的 IP

    while(1)
    {
        sprintf(buff,"num:%d",num++);
        sendto(fd,buff,sizeof(buff),0,(struct sockaddr *)&R_addr,sizeof(R_addr));
        perror("sendto()");
        sleep(1);
    }
  • 广播接收方
struct sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);
    addr.sin_addr.s_addr = INADDR_ANY;
    bind(fd, (struct sockaddr*)&addr,sizeof(addr));

    char buff[50]={0};
    struct sockaddr_in S_addr = {0};
    int len = sizeof(S_addr);

    while(1)
    {
        recvfrom(fd,buff,sizeof(buff),0,(struct sockaddr*)&S_addr,
        &len);
        printf("IP:%s\n",inet_ntoa(S_addr.sin_addr));
        //将大端转化为小端
        printf("PORT:%d\n",ntohs(S_addr.sin_port));
        printf("接收到:%s\n",buff);
    }
  • 组播发送方
char buff[30]={0};
    int num = 0;


    struct sockaddr_in R_addr = {0};
    R_addr.sin_family = AF_INET;
    R_addr.sin_port = htons(PORT);//发送的端口
    R_addr.sin_addr.s_addr = inet_addr(IP);//发送的 IP

    
    while(1)
    {
        sprintf(buff,"num:%d!!!",num++);
        sendto(fd,buff,sizeof(buff),0,(struct sockaddr *)&R_addr,sizeof(R_addr));
        perror("sendto()");
        sleep(1);

    }
    
  • 组播接收方
struct sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);
    addr.sin_addr.s_addr = INADDR_ANY;
    bind(fd, (struct sockaddr*)&addr,sizeof(addr));

    struct ip_mreqn addr1 = {0};
    addr1.imr_address.s_addr = INADDR_ANY;
    addr1.imr_multiaddr.s_addr = inet_addr("224.2.2.2");
    setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&addr1,sizeof(addr1));

    char buff[50]={0};
    struct sockaddr_in S_addr = {0};
    int len = sizeof(S_addr);

    while(1)
    {
        recvfrom(fd,buff,sizeof(buff),0,(struct sockaddr*)&S_addr,&len);
        printf("IP:%s\n",inet_ntoa(S_addr.sin_addr));
        //将大端转化为小端
        printf("PORT:%d\n",ntohs(S_addr.sin_port));
        printf("接收到:%s\n",buff);
    }

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

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

相关文章

24:【stm32】DMA数据搬运

DMA数据搬运 1、DMA的简介2、STM32中的DMA结构3、案列3.1、将数组DataA中的数据搬运到DataB中3.2、ADC扫描模式DMA 1、DMA的简介 DMA是直接存储器存取&#xff0c;它可以提供外设寄存器和存储器&#xff0c;存储器与存储器之间的高速数据的传输&#xff0c;无需CPU的干预&…

通配符证书的申请及配置教程

在当今高度互联的世界里&#xff0c;网站和应用程序需要确保其数据传输的安全性&#xff0c;以保护用户的隐私和敏感信息不被窃取。为此&#xff0c;HTTPS协议成为了标准配置&#xff0c;而SSL/TLS证书则是实现这一安全协议的重要组成部分。特别地&#xff0c;对于那些运营着多…

asp.net core web api项目添加自定义中间件

前言 在asp.net core web api项目中&#xff0c;默认提供了很多的中间件&#xff0c;比如访问静态文件中间件UseStaticFiles&#xff0c;跨域配置中间件UseCors&#xff0c;路由中间件UseRouting,身份验证中间件UseAuthentication。 那么如何添加一些自定义的中间件呢。 需求…

【数据结构】单链表功能的实现

目录 1.链表的概念及结构 2.单链表功能的实现 2.1打印单链表 2.2创建节点 2.3单链表尾插 2.3单链表头插 2.5单链表尾删 2.6单链表头删 2.7单链表的查找 2.8在指定位置之前插入数据 2.9在指定位置之后插入数据 2.10删除pos节点 2.11删除pos之后的节点 2.12销毁链表…

快专利与慢专利:速度与质量的天平

在当今快速发展的科技时代&#xff0c;专利成为了创新成果的重要保护手段。然而&#xff0c;不同的创新有着不同的节奏&#xff0c;由此也产生了“快专利”与“慢专利”之分。快专利以其迅速的申请和应用&#xff0c;为创新者抢占市场先机&#xff1b;慢专利则凭借深度的研发和…

Django Admin后台从一个页面同时编辑多个模型

要从Django Admin后台一个页面同时编辑多个对象&#xff0c;我们需要使用内联。 假设你有一个Category模型&#xff0c;并且需要在Admin后台Category编辑页面&#xff0c;同时编辑Villain模型。你可以在admin.py中使用内联&#xff1a; class VillainInline(admin.StackedInl…

EDIUS X 10.34.9631 视频剪辑软件 下载 包含安装说明

下载地址(资源制作整理不易&#xff0c;下载使用需付费&#xff0c;不能接受请勿浪费时间下载) 链接&#xff1a;https://pan.baidu.com/s/1P2wKxVcSx5WzAtHXCaAp5A?pwd227i 提取码&#xff1a;227i

自动控制:鲁棒控制的原理和设计

自动控制&#xff1a;鲁棒控制的原理和设计 引言 在实际控制系统中&#xff0c;由于模型不确定性、外部扰动、参数变化等因素&#xff0c;传统的控制方法难以保证系统在各种情况下的性能。这时&#xff0c;鲁棒控制&#xff08;Robust Control&#xff09;应运而生。鲁棒控制…

Vue(十一)默认插槽、具名插槽、作用域插槽

文章目录 一、需求二、插槽1. 默认插槽2. 具名插槽3. 作用域插槽 一、需求 有三个Category组件&#xff0c;展示不同的内容。 需求&#xff1a;美食模块需要展示图片&#xff0c;游戏模块还是文字&#xff0c;电影模块展示预告片。 <!--App组件--> <template>&l…

四款录音神器,你选对了吗?

在快节奏的现代生活中&#xff0c;我们经常需要处理大量的录音文件&#xff0c;如会议记录、采访、讲座等。为了更高效地处理这些信息&#xff0c;录音转文字工具变得越来越重要。本文将为大家介绍四款常用的录音转文字工具&#xff0c;并分享使用体验。 一、福昕PDF转换器 直…

Matlab 并联双振子声子晶体梁结构带隙特性研究

参考文献&#xff1a;吴旭东,左曙光,倪天心,等.并联双振子声子晶体梁结构带隙特性研究[J].振动工程学报,2017,30(01):79-85. 为使声子晶体结构实现范围更宽的多带隙特性&#xff0c;基于单振子型声子晶体结构弯曲振动带隙频率范围窄的局 限&#xff0c;提出了一种双侧振子布置…

电商智能分析:阿里巴巴商品详情API返回值的挖掘与利用

电商智能分析是利用大数据和机器学习技术来深入理解用户行为、商品趋势以及市场变化的过程。阿里巴巴商品详情API作为获取商品详细信息的重要工具&#xff0c;其返回值中蕴含了丰富的数据&#xff0c;可以通过挖掘和利用这些数据来进行智能分析。下面&#xff0c;我将提供一个基…

美畅物联丨科技赋能校车安全:智慧监控管理系统的创新应用

1、背景 1.1应用需求 孩子&#xff0c;作为国家未来的希望之星和民族发展的潜力所在&#xff0c;其安全与健康向来都是社会瞩目的核心要点。校车&#xff0c;作为孩子们日常出行的关键交通载体&#xff0c;其安全性更是时刻牵动着每一个家庭的敏感神经。然而&#xff0c;不可…

TensorFlow1和TensorFlow2介绍

目录 一.安装 二.TensorFlow结构分析 数据流图介绍 三.图与TensorBoard 1.图结构 2.图的相关操作 3.自定义图 4.开启会话Session中指定使用那个图 四.TensorBoard&#xff1a;可视化 1.数据序列化-events文件 2.启动TensorBoard 3.tensorflow2中使用tensorboard 1.…

【编程基础C++】素数判定、最小公倍数与最大公因数的实现方法

文章目录 素数法一法二 最大公因数辗转相除法另一写法 最小公倍数直接枚举法根据GCD算LCM 素数 素数 是指大于1的自然数&#xff0c;且只能被1和自身整除。例如&#xff0c;2、3、5和7都是素数。它们在数学中非常重要&#xff0c;因为任何大于1的自然数都可以唯一地表示为素数…

【类模板】成员函数模板

一、成员函数模板的基本含义 不管是普通的类&#xff0c;还是类模板&#xff0c;都可以为其定义成员函数模板&#xff0c;以下的情况就是类模板和成员函数模板都有各自独立的一套参数&#xff1a; template<typename T1> class A { public:T1 m_ic;static constexpr int…

电力104规约

对象性质十进制十六进制数量适用报文类型ASDU遥测1793~2304701H~900H512*9、11、21、34、35遥信1~10241H~400H1024*1、3、20、30、31遥控2817~2944B01H~B80H128*45、46遥调2945~3072B81H~C00 H128*47APCI 应用规约控制信息; ASDU 应用服务数据单元; APDU 应用规约数据单元;…

CountDownLatch的应用与原理

一、什么是CountDownLatch CountDownLatch是具有synchronized机制的一个工具&#xff0c;目的是让一个或者多个线程等待&#xff0c;直到其他线程的一系列操作完成。 CountDownLatch初始化的时候&#xff0c;需要提供一个整形数字&#xff0c;数字代表着线程需要调用countDow…

K8s系列之:解释Kubernetes Operators

K8s系列之&#xff1a;解释Kubernetes Operators 什么是控制器循环&#xff1f;Kubernetes Operator是如何工作的&#xff1f;如何添加自定义资源自定义资源定义Kubernetes Operators&#xff1a;案例研究 你是否曾想过&#xff0c;Site Reliability Engineering&#xff08;SR…

【优化】Nginx 配置页面请求不走缓存 浏览器页面禁用缓存

【优化】Nginx 配置页面请求不走缓存 禁用缓存 目录 【优化】Nginx 配置页面请求不走缓存 禁用缓存 对所有请求禁用缓存 对特定location禁用缓存 注意事项 全局禁用缓存 要配置Nginx使其不缓存内容&#xff0c;通常是指禁止浏览器缓存响应的内容&#xff0c;或者是在代理…