[UDP教程] 如何实现IPv4下的UDP广播

简介

写了一个UDP广播的代码。
IPv4一个,IPv6一个。
编译环境是linux C++11。

文件构成

ser.cpp用于发送广播。
cli.cpp用于接收广播。

build_cli.sh和build_svr.sh是编译脚本。

./cli 等待接收广播数据
./svr 执行发送广播

代码实现

IPv4, 发送广播

//使用的广播地址是"255.255.255.255",路由不会转发

int UDP_Controler::BroadCast()
    {
        if (m_ctl_type != ctl_unknowtype && m_ctl_type != ctl_broadcast_send)
        {
            LOGS << "Type error" << LOGE;
            return -1;
        }
        int iset = 1;
        if (setsockopt(m_local_fd, SOL_SOCKET, SO_BROADCAST, &iset, sizeof(iset)))
        {
            perror("setsockopt");
            return -1;
        }

        char buff[MIN_BUFFSISE] = {0x00};
        sprintf(buff, "%s", "@TEST GETJOB \r\n");

        sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = inet_addr("255.255.255.255");
        addr.sin_port = htons(9100);
        int res = sendto(m_local_fd, buff, strlen(buff), 0,
                         (sockaddr *)&addr, sizeof(addr));
        if (res == -1)
        {
            perror("sendto");
            return -1;
        }
        LOGS << "send broadcast msg:" << buff << "." << LOGE;
        m_ctl_type = ctl_broadcast_send;
        return 0;
    }

IPv4, 接收广播

//使用的广播地址是"255.255.255.255",路由不会转发

int UDP_Controler::BroadCast_Recv()
    {
        if (m_ctl_type != ctl_unknowtype && m_ctl_type != ctl_broadcast_recv)
        {
            LOGS << "Type error" << LOGE;
            return -1;
        }

        char buff[MIN_BUFFSISE] = {0x00};
        sockaddr_in local_addr, addr;
        socklen_t len = sizeof(sockaddr_in);
        local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
        local_addr.sin_port = htons(9100);
        local_addr.sin_family = AF_INET;

        if(bind(m_local_fd, (sockaddr*)&local_addr, len) == -1) {
            perror("bind");
            return -1;
        }

        int res = recvfrom(m_local_fd, buff, MIN_BUFFSISE, 0,
                           (sockaddr *)&addr, &len);
        if (res == 0)
        {
            perror("recvfrom return 0");
            return -1;
        }
        else if (res == -1)
        {
            perror("recvfrom return -1");
            return -1;
        }
        LOGS << "recv broadcast msg:" << buff << ",from:" << inet_ntoa(addr.sin_addr) << ":" << ntohs(addr.sin_port) << LOGE;
            
        m_ctl_type = ctl_broadcast_recv;
        return res;
    }

IPv6 ,发送广播

//唯有sockaddr 部分和IPv4不同
// "FF02::1"是IPv6链路本地广播地址,不可跨越路由器

int UDP_Controler::BroadCast()
    {
        if (m_ctl_type != ctl_unknowtype && m_ctl_type != ctl_broadcast_send)
        {
            LOGS << "Type error" << LOGE;
            return -1;
        }
        int iset = 1;
        if (setsockopt(m_local_fd, SOL_SOCKET, SO_BROADCAST, &iset, sizeof(iset)))
        {
            perror("setsockopt");
            return -1;
        }

        char buff[MIN_BUFFSISE] = {0x00};
        sprintf(buff, "%s", "FF02::1");

        sockaddr_in6 addr;
        addr.sin6_family = AF_INET6;
        int res = inet_pton(AF_INET6, buff, &addr.sin6_addr);
        if(res <= 0) {
            perror("inet_pton");
            return -1;
        }
        addr.sin6_port = htons(9100);
        addr.sin6_scope_id = if_nametoindex("ens33");

        bzero(buff,MIN_BUFFSISE);
        sprintf(buff, "%s", "@TEST IPV6 GETJOB \r\n");
        res = sendto(m_local_fd, buff, strlen(buff), 0,
                         (sockaddr *)&addr, sizeof(addr));
        if (res == -1)
        {
            perror("sendto");
            return -1;
        }
        LOGS << "send broadcast msg:" << buff << "." << LOGE;
        m_ctl_type = ctl_broadcast_send;
        return 0;
    }

IPv6, 接收广播

//唯有sockaddr 不分和IPv4不同
// "FF02::1"是IPv6链路本地广播地址,不可跨越路由器

 int UDP_Controler::BroadCast_Recv()
    {
        if (m_ctl_type != ctl_unknowtype && m_ctl_type != ctl_broadcast_recv)
        {
            LOGS << "Type error" << LOGE;
            return -1;
        }

        char buff[MIN_BUFFSISE] = {0x00};
        sockaddr_in6 local_addr, addr;
        socklen_t len = sizeof(sockaddr_in6);
        local_addr.sin6_addr = in6addr_any;
        local_addr.sin6_port = htons(9100);
        local_addr.sin6_family = AF_INET6;

        if(bind(m_local_fd, (sockaddr*)&local_addr, len) == -1) {
            perror("bind");
            return -1;
        }

        int res = recvfrom(m_local_fd, buff, MIN_BUFFSISE, 0,
                           (sockaddr *)&addr, &len);
        if (res == 0)
        {
            perror("recvfrom return 0");
            return -1;
        }
        else if (res == -1)
        {
            perror("recvfrom return -1");
            return -1;
        }
        char addrv6[128] = { 0x00 };
        inet_ntop(AF_INET6, &addr.sin6_addr , addrv6, 128 );
        LOGS << "recv broadcast msg:" << buff << ",from:" << addrv6 << ":" << ntohs(addr.sin6_port) << LOGE;
            
        m_ctl_type = ctl_broadcast_recv;
        return res;
    }

完整代码:
查看链接资源。

物联沃分享整理
物联沃-IOTWORD物联网 » [UDP教程] 如何实现IPv4下的UDP广播

发表评论