先说下结论,

WIFI 单播与组播的对比

802.11 只有 unicast 和 broadcast。UDP 广播以及组播在实际传输上,根据设置的不同,可以被操作系统自动转换成 unicast 和 broadcast。转成 unicast 的好处很明显:

1. 可以使用 multi stream。即多个空间流传输,能够达到无线的标称速率比如:433Mbps/866Mbps

2. 可靠性比 broadcast 高,因为每一个包对会有物理层的 ACK。

3. 可以使用 802.11n 之后的高级特性,比如 A-MPDU,A-MSDU 等。

缺点也很明显,有多个 client 的时候,每个都要这样传输一遍,很占空域时间。实际上 OpenWrt 等路由器的默认广播 /组播就是用 unicast 发送的,要想修改可以参考如下: https://wiki.openwrt.org/doc/howto/udp_multicast。

使用 multcast 发送的好处如下:

wifi android广播 wifi无线广播_广播

最近再做一个项目,要求WIFI AP实时的向客户端发送UDP数据,有时候可能会存在很多这样的客户端,而发送的数据一样, 这不就是要发送广播包吗?毫不犹豫的使用了UDP广播包发送,但是测试过程中发现个问题,会不定时丢包,每500ms发1包,1分钟120包,总会丢那么三五包, 如果距离离的远的话,会丢的更多,即使客户端就放在AP旁边也会丢几包。

于是就开始了漫长的查问题。

1,模拟测试环境,直接使用电脑与路由器来测试,发现如果用UDP广播 发送的话,一样会丢包,  看来是UDP广播的特性,不保证成功率, 如果使用UDP点到点传输的话,会好很多。  看来使用广播发送更加剧了不确定性。

2. 虽然UDP广播包会丢包,但是ping非常稳定,不会超时,不会丢包,如下图,连续ping了半个小时,1包没有丢。

3.  上面2者对比,我就很困惑, UDP广播为什么会丢呢?  而同样发送的ping包却1包不丢, 就是wifi底层协议的问题?  一时也解决不了了问题,好在不耽误应用, 

ping是没问题的

wifi android广播 wifi无线广播_UDP_02

下面可以看出丢了4E这包数据, 但此时网络是通的。

wifi android广播 wifi无线广播_广播_03

下面是周期性发送UDP广播包的的程序,在我的嵌入式linux上已经正常运行。

这个程序调试过程花费了我很多时间,也是没有想到的,主要有2点

1. 新建socket绑定在INADDR_ANY也就是0.0.0.0时, 是不能发送到255.255.255.255的广播包的,只能发送到网段的广播包,如192.168.111.255

2. 要想发送255.255.255.255的广播包,必须绑定一个IP地址,我猜其实是绑定一个本地网卡,

(结论: 一个socket,即不知道源地址,也不知道目的地址, 是发送不成功的,因为系统不知道这包数据应该从哪个网卡发出去。我当时调用sendto(),一直返回-1)

#include <unistd.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <errno.h>
 #include <string.h>
 /* According to POSIX.1-2001, POSIX.1-2008 */
 #include <sys/select.h>
 /* According to earlier standards */
 #include <sys/time.h>
 #include <stdbool.h>
 #include <time.h>#define MYPORT1 3060
void main()
 {
     struct sockaddr_in locaddr, servaddr;
     socklen_t nRecLen;
     int sock1;
     int i;
     uint8_t data=0;
      int so_broadcast=1;
      int ret;
     
     char recv_buf[2048];    // 接收缓冲区
     char snd_buf[128];    //int nRecLen; // 客户端地址长度!!!!
    if ((sock1 = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
         printf("socket()\n");
     printf("sock1: %d creat OK\n", sock1);        ret = setsockopt(sock1, SOL_SOCKET, SO_BROADCAST, &so_broadcast, sizeof(so_broadcast));
         printf("setsockopt()  %d\r\n", ret);
                   
     memset(&locaddr, 0, sizeof(locaddr));
     locaddr.sin_family = AF_INET;
     locaddr.sin_port = htons(MYPORT1);
     locaddr.sin_addr.s_addr = inet_addr("192.168.111.1");    //htonl(INADDR_ANY);
     if (bind(sock1, (struct sockaddr *)&locaddr, sizeof(locaddr)) < 0)
     {
         printf("blind error\r\n");
     }
     else{
         printf("listening %d port\r\n",MYPORT1);
     }
     
     
     memset(&servaddr, 0, sizeof(servaddr));
     servaddr.sin_family = AF_INET;
     servaddr.sin_port = htons(3062);
     servaddr.sin_addr.s_addr = inet_addr("255.255.255.255");  
   
     
     while(1)
     {
         sleep(1);
         ret = sendto(sock1, snd_buf, sizeof(snd_buf), 0, (struct sockaddr *)&servaddr, sizeof(servaddr));
         memset(snd_buf, data, sizeof(snd_buf));
         data++;
         printf("sendto  %02X return %d\r\n", data, ret);
         
     }
 }

就是在这货身上调试的。

wifi android广播 wifi无线广播_广播_04