IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> linux socket UDP广播 -> 正文阅读

[网络协议]linux socket UDP广播

概述:
网络上的广播指:由一台主机向该主机所在子网内(同一个局域网)的所有主机发送数据的方式

实现广播,离不开广播地址,同一个子网(局域网)的所有主机网卡都会接收所在网段广播地址的数据包。广播地址应用于局域网内的所有主机。

广播地址(Broadcast Address)==专门用于同时向网络中(通常指同一子网)所有工作站进行发送的一个地址

1. 网络通信基础

如果网络中两个主机上的应用程序要相互通信,其一要知道彼此的IP,其二要知道程序可监听的端口。因为同一主机上的程序使用网络是通过端口号来区分的。

2. 广播地址

2.1 受限广播(本地广播)

路由器从来不会转发受限广播的数据包,但同一个子网的所有主机都会接收到受限广播的数据包。

本地广播: IP 地址的网络字段和主机字段全为 1 就是受限广播地址255.255.255.255。,它不经路由转发,发送本地网络下的所有主机,只能在局域网内转发,主要是不用知道目标主机的掩码与网络地址,本地转发同本地网络下的所有主机。

2.2 直接广播

计算方法通过主机的掩码与网络地址计算出来。掩码最后为0的位为主机位。掩码与网络地址相与,然后主机位全变为1,就是直接广播地址。这样改网络地址下的所有主机都能接收到广播。可以通过ifconfig查看,如下图所示:
在这里插入图片描述

直接广播可以被路由转发,发送到目标网络的所有主机,如:ip地址为 192.168.2.1的主机也可以发送广播到 192.168.1.0 这个网络。当然不是所有的路由器,通常路由器是默认阻止直接广播的(可以设置不阻止)。

IP 地址的网络字段定义这个网络,主机字段通常全为 1,如192.168.10.0/24 的直接广播(定向广播)地址为:192.168.10.255。

2.3 受限广播与直接广播的区别

两者的区别就是,本地广播在不知道目标主机的网络地址下,如果目标主机是在本地网络,可以发送本地广播,本地网络下的所有主机都能接收广播。直接广播是目标主机的网络地址知道,那该网络地址网段下的所有主机都能收到广播,直接广播更精确范围更小些

3. 广播特点

3.1 广播分为两端,即数据发送端和数据接收端,通过广播的方式发送数据,发送端和接收端的关系是 1:N

3.2发送广播消息的一端,通过广播地址,可以将消息同时发送到局域网的多台主机上(数据接收端)

3.3 在发送广播消息的时候,必须要把数据发送到广播地址上

3.4 广播只能在局域网内使用,广域网是无法使用UDP进行广播的

3.5 只要发送端在发送广播消息,数据接收端就能收到广播消息,消息的接收是无法拒绝的,除非将接收端的进程关闭,就接收不到了。当端口不匹配的话,数据才会丢弃

UDP 的广播和日常生活中的广播是一样的,都是一种快速传播消息的方式,因此广播的开销很小,发送端使用一个广播地址,就可以将数据发送到多个接收数据的终端上,如果不使用广播,就需要进行多次发送才能将数据分别发送到不同的主机上。

4. 设置UDP广播属性

基于 UDP 虽然可以进行数据的广播,但是这个属性默认是关闭的,如果需要对数据进行广播,那么需要在广播端代码中开启广播属性,需要通过套接字选项函数setsockopt进行设置

/*
函数:setsockopt
描述:设置广播属性
参数:
	sockfd:进行 UDP 通信的文件描述符
	level: 套接字级别,需要设置为 SOL_SOCKET
	optname:选项名,此处要设置 udp 的广播属性,该参数需要指定为:SO_BROADCAST
	optval:如果是设置广播属性,该指针实际指向一块 int 类型的内存
		该整型值为 0:关闭广播属性
		该整形值为 1:打开广播属性
	optlen:optval 指针指向的内存大小,即:sizeof(int)
	
返回值:函数调用成功返回 0,失败返回 - 1
*/
int setsockopt(int sockfd, int level, int optname, 	const void *optval, socklen_t optlen);

5. 广播流程

假如我们要向192.168.200.X,子网掩码为:255.255.255.0的子网中发送广播包。

***广播端步骤如下:
1.       include相关库文件。
2.       socket函数创建SOCK_DIRAM类型的socketfd。
3.       setsockopt设置socketfd的属性允许其广播。
4.       发送数据包到192.168.200.255
5.       关闭socketfd
注意事项如下:
6.       接收方一定要知道广播方的端口号,然后绑定此端口号才能正确接收。接收端的端口号要与广播端绑定的端口号一样
7.       接收方的Socket不需要设置成广播属性。
8.       绑定的IP不可以使用“127.0.0.1”,可以使用真实IP地址或者INADDR_ANY。否则接收失败

***接收端步骤
1.       include相关库文件。
2.       socket函数创建SOCK_DIRAM类型的socketfd。
3. 		 bind绑定端口号与本地IP地址
4. 	     接收广播端数据
5.	     关闭socketfd

在这里插入图片描述

6 代码举例

6.1 广播端代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>

int main()
{
    // 1. 创建通信的套接字
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd == -1)
    {
        perror("socket");
        exit(0);
    }

    // 2. 设置广播属性
    int opt  = 1;
    setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt));

    char buf[1024];
    struct sockaddr_in cliaddr;
    int len = sizeof(cliaddr);
    cliaddr.sin_family = AF_INET;
    cliaddr.sin_port = htons(9999); // 接收端需要绑定9999端口
    // 只要主机在237网段, 并且绑定了9999端口, 这个接收端就能收到广播消息
    inet_pton(AF_INET, "192.168.200.255", &cliaddr.sin_addr.s_addr);//
//	inet_pton(AF_INET, "255.255.255.255", &cliaddr.sin_addr.s_addr);	//使用受限广播也可以正常通讯
    // 3. 通信
    int num = 0;
    while(1)
    {
        sprintf(buf, "hello client : %d\n", num++);
        // 数据广播
        sendto(fd, buf, strlen(buf)+1, 0, (struct sockaddr*)&cliaddr, len);
        printf("发送的广播的数据: %s\n", buf);
        sleep(1);
    }

    close(fd);

    return 0;
}

6.2 接收端代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>

int main()
{
    // 1. 创建通信的套接字
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd == -1)
    {
        perror("socket");
        exit(0);
    }

    // 2. 通信的套接字和本地的IP与端口绑定
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(9999);    // 大端
    addr.sin_addr.s_addr = INADDR_ANY;  // 0.0.0.0
    int ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
    if(ret == -1)
    {
        perror("bind");
        exit(0);
    }

    char buf[1024];
    // 3. 通信
    while(1)
    {
        // 接收广播消息
        memset(buf, 0, sizeof(buf));
        // 阻塞等待数据达到
        recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL);
        printf("接收到的广播消息: %s\n", buf);
    }
    close(fd);
    return 0;
}

参考于:

  1. https://subingwen.cn/linux/broadcast/#4%E9%80%9A%E4%BF%A1%E4%BB%A3%E7%A0%81
  2. https://blog.csdn.net/weixin_43790540/article/details/104239594
  3. https://blog.csdn.net/maopig/article/details/7331898
  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-08-17 15:45:03  更:2021-08-17 15:45:40 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/28 6:30:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计