1.引言

网络通信中使用最多的就是广播、组播、单播几种通信方式了,今天我们抛开具体的标准和知识,简单聊聊单播、组播、广播的区别与使用。

2.单播、组播、广播区别与联系

单播:在同一网络内,两个设备点对点的通信就是单播通信。

组播:在同一网络可达范围内,一个网络设备与关心其数据的部分设备进行通信就是组播。

广播:在同一网络可达范围内,一个网络设备向本网络内所有设备进行通信就是广播。

具体如下:

简单地说,单播->组播->广播,是通信数量不断增加的通信方式。当然,通信数量的增多,带来的是通信设备的资源消耗更大,整体网络环境的复杂度更高。

通常,我们使用组播、广播完成两件事:

1)将同一份数据交互到多个目的地。比如,视频会议、新闻分发,都需要将一份数据同时传输到多个设备上,供大家使用。

2)通过客户端请求或发现服务器。有时,我们并不知道服务器的具体信息(如IP地址),这时,我们可以采取“盲发”的方式去广播或组播信息,等待服务器收到消息盲发的消息后,返回数据,如此找到对应目标设备。

众所周知,TCP是可靠传输(先与另一个通信端点建立可靠连接,再传输数据),因此TCP一般只支持单播这种通信方式,而DUP通信不需要建立连接就可以发送数据,因此,通常我们说的广播、组播,都是在UDP下概念。

此外,广播又可以分为两类:本地广播、定向广播。

1)本地广播:广播地址为255.255.255.255.

2)定向广播:广播地址类似192.168.4.255.

这两种广播功能类似,但具体区别说来话长,有感兴趣的可以留言,我再出篇帖子来介绍一下。

3.编程与测试

广播、单播在实现方式,以及使用方式上的区别不大,仅仅是目标IP,以及Socket属性的细微差别,我们先来看两者的区别与使用。

具体可参考以下代码:(开发板仍然是便宜且好用的ESP32开发板,开发环境是release V4.2,实际上,任何平台,以下代码都是可以参考滴,客官慢用)

/* BSD Socket API ExampleThis example code is in the Public Domain (or CC0 licensed, at your option.)Unless required by applicable law or agreed to in writing, thissoftware is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES ORCONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "protocol_examples_common.h"#include "tcpip_adapter.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include <lwip/netdb.h>
#include "addr_from_stdin.h"#if defined(CONFIG_EXAMPLE_IPV4)
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV4_ADDR
#elif defined(CONFIG_EXAMPLE_IPV6)
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV6_ADDR
#else
#define HOST_IP_ADDR ""
#endif#define PORT CONFIG_EXAMPLE_PORTstatic const char *TAG = "example";
static const char *payload = "Message from ESP32 ";static int udp_creat(uint16_t port, char* bind_ip)
{struct sockaddr_in6 unicast_dest_addr = {0};struct sockaddr_in *unicast_dest_addr_ip4 = (struct sockaddr_in *)&unicast_dest_addr;int ip_protocol = 0;const int on = 1;inet_aton(bind_ip, &unicast_dest_addr_ip4->sin_addr.s_addr);//bind sta ipunicast_dest_addr_ip4->sin_family = AF_INET;unicast_dest_addr_ip4->sin_port = htons(port);ip_protocol = IPPROTO_IP;int sock = socket(AF_INET, SOCK_DGRAM, ip_protocol);if (sock < 0) {ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);return -1;}int err = bind(sock, (struct sockaddr *)&unicast_dest_addr, sizeof(unicast_dest_addr));if (err < 0) {ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);shutdown(sock, 0);close(sock);return -1;}if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) {ESP_LOGE(TAG, "reuse addr fail");close(sock);return -1;}if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) != 0) {ESP_LOGE(TAG, "broadcast enable fail");close(sock);return -1;}return sock;
}static void udp_client_task(void *pvParameters)
{char rx_buffer[128];char host_ip[] = HOST_IP_ADDR;int addr_family = 0;int ip_protocol = 0;tcpip_adapter_ip_info_t sta_info;while (1) {#if defined(CONFIG_EXAMPLE_IPV4)struct sockaddr_in unicast_dest_addr;unicast_dest_addr.sin_addr.s_addr = inet_addr(HOST_IP_ADDR);unicast_dest_addr.sin_family = AF_INET;unicast_dest_addr.sin_port = htons(PORT);addr_family = AF_INET;ip_protocol = IPPROTO_IP;
#elif defined(CONFIG_EXAMPLE_IPV6)struct sockaddr_in6 unicast_dest_addr = { 0 };inet6_aton(HOST_IP_ADDR, &unicast_dest_addr.sin6_addr);unicast_dest_addr.sin6_family = AF_INET6;unicast_dest_addr.sin6_port = htons(PORT);unicast_dest_addr.sin6_scope_id = esp_netif_get_netif_impl_index(EXAMPLE_INTERFACE);addr_family = AF_INET6;ip_protocol = IPPROTO_IPV6;
#elif defined(CONFIG_EXAMPLE_SOCKET_IP_INPUT_STDIN)struct sockaddr_in6 unicast_dest_addr = { 0 };ESP_ERROR_CHECK(get_addr_from_stdin(PORT, SOCK_DGRAM, &ip_protocol, &addr_family, &unicast_dest_addr));
#endifchar sta_ip_str[32] = {0};esp_err_t ret = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &sta_info);if (ret != ESP_OK) {ESP_LOGE(TAG, "get sta ip fail");}printf(IPSTR, IP2STR(&sta_info.ip));sprintf(sta_ip_str, IPSTR, IP2STR(&sta_info.ip));int sock = udp_creat(3333,sta_ip_str);if (sock < 0) {ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);break;}ESP_LOGI(TAG, "Socket created, sending to %s:%d", HOST_IP_ADDR, PORT);struct sockaddr_in broadcast_dest_addr;//for broadcastchar sendline[32] = {"Hello"};char temp_str[32] = "255.255.255.255";bzero(&broadcast_dest_addr, sizeof(broadcast_dest_addr));broadcast_dest_addr.sin_family = AF_INET;broadcast_dest_addr.sin_addr.s_addr = inet_addr(temp_str); //广播地址(192.168.43.255 can be work, too.)broadcast_dest_addr.sin_port = htons(3333);//target portwhile (1) {int err = sendto(sock, sendline, strlen(sendline), 0, (struct sockaddr*)&broadcast_dest_addr, sizeof(broadcast_dest_addr));//broadcastif (err < 0) {ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);break;}ESP_LOGI(TAG, "Message sent");err = sendto(sock, payload, strlen(payload), 0, (struct sockaddr *)&unicast_dest_addr, sizeof(unicast_dest_addr));//unicastif (err < 0) {ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);break;}ESP_LOGI(TAG, "Message sent");struct sockaddr_in source_addr; // Large enough for both IPv4 or IPv6socklen_t socklen = sizeof(source_addr);int len = recvfrom(sock, rx_buffer, sizeof(rx_buffer) - 1, 0, (struct sockaddr *)&source_addr, &socklen);// Error occurred during receivingif (len < 0) {ESP_LOGE(TAG, "recvfrom failed: errno %d", errno);break;}// Data receivedelse {rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a stringESP_LOGI(TAG, "Received %s", rx_buffer);if (strncmp(rx_buffer, "OK: ", 4) == 0) {ESP_LOGI(TAG, "Received expected message, reconnecting");break;}}vTaskDelay(2000 / portTICK_PERIOD_MS);}if (sock != -1) {ESP_LOGE(TAG, "Shutting down socket and restarting...");shutdown(sock, 0);close(sock);}}vTaskDelete(NULL);
}void app_main(void)
{ESP_ERROR_CHECK(nvs_flash_init());ESP_ERROR_CHECK(esp_netif_init());ESP_ERROR_CHECK(esp_event_loop_create_default());/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.* Read "Establishing Wi-Fi or Ethernet Connection" section in* examples/protocols/README.md for more information about this function.*/ESP_ERROR_CHECK(example_connect());xTaskCreate(udp_client_task, "udp_client", 4096, NULL, 5, NULL);
}

上述代码,通过UDP,实现广播、单播一次,然后进入接收一次数据;依次循环的功能。

4.组播实现介绍

组播的实现就略微复杂了,要实现组播,至少要经过以下步骤:

1)建立socket_fd

2)socket_fd和指定本地端口绑定

3)加入一个组播组

4)通过sendto / recvfrom进行数据的收发

5)离开组播组

6)关闭socket

注意:服务器和客户端必须都要加入相同的组播地址才可以。涉及到的socket属性主要是以下三个:

感兴趣的小伙伴可以留言,我将再出一篇关于组播的博客,谢谢点赞或收藏。

广播、组播、单播区别与联系相关推荐

  1. 单播 广播 组播区别

    一:通信方式分类 在IPv4网络中,主机可采用的通信方式有如下三种: 1.单播:单台主机与单台主机之间的数据通信 带宽端口有多少台就发多少个数据 2.广播:单台主机向网络中所有主机发送数据包的过程 发 ...

  2. 组播,单播,广播,多播,泛洪的概念

    一.什么是组播: 1.组播的特点 1)什么是组播?       组播是一种数据包传输方式,当有多台主机同时成为一个数据包的接受者时,出于对带宽和CPU负担的考虑,组播成为了一种最佳选择. 2)组播如何 ...

  3. 单播 广播 组播_【技术解析】关于组播概念那些你需要知道的~

    点击蓝字关注我 今天,小盟带大家继续学习一下组播知识~ 一.IGMP Message 1.组成员一旦开启IGMP,会自动发送Membership Report消息到叶路由器 2.IGMPv2版本,组成 ...

  4. 动态路由协议的分类、动静态路由优缺点、RIP简介、组播单播广播详解(附图)

    目录 一.动态路由协议的分类 (1)按照工作区域范围: (2)按照路由算法: RIP相关知识简介: 二.静态路由优缺点: 三. 动态路由优缺点: 四.单播.组播.广播详解: 一.动态路由协议的分类 ( ...

  5. 单播 广播 组播_组播概念3

    一.IGMP Message 1.组成员一旦开启IGMP,会自动发送Membership Report消息到叶路由器 2.IGMPv2版本,组成员退出组会发送leave消息,IGMPv1不会 3.也就 ...

  6. 域服务器广播消息,广播,组播和UNIX域套接字

    1.广播 1.特点 一对多 仅能使用UDP 2.概念 发送方只有一个接收方则称单播 如果同时发给局域网中的所有主机,成为广播 只有用户数据包(使用UDP协议)套接字才能广播 广播地址 1.以192.1 ...

  7. UDP通信多发多收(案例)和广播组播

    使用UDP通信方式开发接收端和发送端(模拟视频弹幕系统) 分析:发送端可以一直发送消息   接收端可以不断的接收多个发送端的消息展示     发送端输入exit则结束发送端程序 UDP的接收端为什么可 ...

  8. java udp 广播 组播_UDP广播和组播的基础知识介绍

    UDP广播和组播的基础知识介绍 ━━━━━━━━━━━━━━━━━━━━━━━━━ UDP可以实现一对多的传输方式,即通过广播和组播把数据发送给一组进程.下面就介绍下UDP广播和组播的相关知识. 一. ...

  9. 【软件通信协议】2. 详细解析UDP通信协议(附广播 组播)

    1. UDP协议简介 UDP是User Datagram Protocol的简称,全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议.在OSI模型中,在第四层--传输层 ...

  10. 广播和多播(组播)的区别

    文章目录 1 定义 2 广播 3 多播 1 定义 广播,简单来说就是一对所有,网络对每一台主机发出的信号都无条件转发,即将数据发送到网络中的每一个主机. 多播,一对一组,只有加入了同一个组的主机才能接 ...

最新文章

  1. 计算机网络的运用在什么时候,离散时间排队系统及其在计算机网络中的应用
  2. 十分钟计算机说课稿,足球十分钟说课稿范文(精选3篇)
  3. Bigtable的些许重点
  4. 金山毒霸的云查杀很牛X
  5. 【计算机组成原理】微处理器、微型计算机、微型计算机系统
  6. 问村民一个什么问题就能决定走哪条路?
  7. R|ggplot2(七)|自定义主题
  8. 四川大学计算机学院2020转专业,四川大学化学学院2020年本科生转专业工作实施方案...
  9. 如何下载并安装 LaTex
  10. 2019/10/8今日头条笔试
  11. 【ios】为什么要在Other Linker Flags添加Flag (eg:-ObjC、-lc++等)?
  12. 树莓派: oled屏幕字体制作
  13. el-cascader级联选择器当子节点的children为空数组的话,有bug(前端解决办法)
  14. 怎么做拼多多活动|成都百择
  15. 【毕业设计_课程设计】在线免费小说微信小程序的设计与实现(源码+论文)
  16. 【appium报错】Original error:Could not proxy command to remote server. Original error:socket hang up
  17. 利用SAH实现kD树快速分割模型实践
  18. monkeyrunner 使用
  19. 一文搞懂内存映射原理及使用方法
  20. 赛门铁克发布全新SEP14解决方案 有效抵御并应对端点网络威胁

热门文章

  1. 证件照换背景-----ps
  2. 解决java:找不到符号办法
  3. html5 获取剪切板内容,H5剪切板功能
  4. java程序员的浪漫代码_java表白代码,能否get到程序员的浪漫?
  5. 服务器虚拟机装nas,nas虚拟主机(nas为什么要装虚拟机)
  6. 【托业】【新托业TOEIC新题型真题】学习笔记12-题库八-P7
  7. php网易云随机音乐api源码开源,网易云音乐随机歌曲
  8. Arduino Uno ADS1115 数模转换
  9. 显著性水平 P值 概念解释
  10. canal 全量数据