WIFI UDP 实时广播 发送数据

先说下结论,

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

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

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

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

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

ping是没问题的

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

下面是周期性发送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);
        
    }
}

就是在这货身上调试的。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值