网络组播及源码

目录

通信流程

组播应用

组播IP地址

组播IP地址的作用

永久组播地址

临时组播地址

本地管理地址

存在问题

代码实现


 

通信流程

                        e0c9edca9c374a95b26e7ffc17162010.png

  • 服务器端
    • 1.创建通信的套接字
      • int fd = socket( af_inet, SOCK_DGRAM, 0)
      1. 绑定 -> 通信的fd 和本地 IP / port 绑定
      • struct sockaddr_in addr;
    • 3.通信
      • 接收数据: recvfrom
      • 发送数据: sendto
    • 4.关闭通信的fd
      • close(fd);
    • 客户端
      • 1.创建一个通信的套接字
      • 2.通信
        • 接收数据: recvfrom
        • 发送数据: sendto
      • 3.关闭通信的文件描述符
        • close();

组播应用

  • 一对多点应用:一对多点应用是指一个发送者,多个接收者的应用形式,这是最常见的多播应用形式。典型的应用包括:媒体广播、媒体推送、信息缓存、事件通知和状态监视等。
  • 多对一应用:多点对点应用是指多个发送者,一个接收者的应用形式。通常是双向请求响应应用,任何一端(多点或点)都有可能发起请求。典型应用包括:资源查找、数据收集、网络竞拍、信息询问等。
  • 多对多应用:多点对多点应用是指多个发送者和多个接收者的应用形式。通常,每个接收者可以接收多个发送者发送的数据,同时,每个发送者可以把数据发送给多个接收者。典型应用包括:多点会议、资源同步、并行处理、协同处理、远程学习、讨论组、分布式交互模拟(DIS)、多人游戏等。

组播IP地址

组播IP地址的作用

标识某一个组播应用/业务(组播源) 代表接收此组播业务的所有主机(接收端) 组播地址为D类地址,

范围是224.0.0.1~239.255.255.255

                c86cfb2153a64bddbc26dfc411cec3b4.png

永久组播地址

所代表的含义已固定,不可更改。

供路由协议、拓扑查找等使用,不用于组播转发。

1150579e60544e45b3c7a2fb7cb33247.png

临时组播地址

组播地址可以被重复使用。

即当一个地址被应用于某个应用时,当此应用关闭不再使用时,此地址就可以被回收,可以被再次应用到其它应用中。

        //复用地址
        int opt = 1;
        if (setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
            LOG(ERROR) << "Failed to set socket options so_reuseaddr.";
            return false;
        }

本地管理地址

仅在本地管理域内有效。

在不同的管理域内重复使用相同的本地管理组地址不会导致冲突

存在问题

主要问题就是丢包和无序

UDP丢包和无序 问题的解决方法 - johnny_HITWH - 博客园 (cnblogs.com)

UDP大批量传输数据时的丢包问题优化_udp发送太快会丢数据-CSDN博客

C++实现udp分包和组包_夏天匆匆2过的博客-CSDN博客

UDP解决丢包问题总结_接收udp组播数据 不丢包怎么实现_GoodLinGL的博客-CSDN博客

网编(20):UDP传输数据经常遇到的问题_udp乱序-CSDN博客

代码实现

Linux C/C++编程:Udp组播(多播)_c udp组播_OceanStar的学习笔记的博客-CSDN博客

Linux C/C++组播_linux组播配置_别,爱℡的博客-CSDN博客

网络组播(Multicast)是一种网络通信模式,允许一组主机(通常称为组成员)通过单一的数据包传输来共享数据。组播通信可以有效地减少网络流量,因为数据只需要一次发送,而不是多次单播或广播。

在组播通信中,每个组成员都加入了一个特定组播组的 IP 地址,而不是单个主机的 IP 地址。发送到这个组播地址的数据包将被传输到所有加入了这个组的主机。组播地址是一个 Class D IP 地址(224.0.0.0 - 239.255.255.255),其中第一个字节是 0xE0 - 0xEF 的范围。

下面是一个使用C++和UDP协议实现网络组播的示例代码。这个示例中有两个程序,一个用于发送消息,另一个用于接收消息。发送程序将消息发送到一个组播地址,接收程序加入了这个组播组,并接收到发送的消息。

发送程序代码:

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>

int main() {
    char group_addr[16]="224.0.0.1";
    int socked=socket(AF_INET,SOCK_DGRAM,0);
    if(socked<0)
    {
        perror("socket failed!");
        return 2;
    }

    struct sockaddr_in remote_addr;
    memset(&remote_addr,0,sizeof(remote_addr));

    remote_addr.sin_family=AF_INET;
    remote_addr.sin_addr.s_addr=inet_addr(group_addr);
    remote_addr.sin_port=htons(5000);

    //设置为广播模式
    int broadcast = 1;
    if (setsockopt(socked, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)) == -1) {
        printf("setsockopt broadcast failed. \n");
        return -1;
    }

    char buf[1024]="This is a group udp";
    int length=0;
    uint32_t cnt=0;
    while(1)
    {
        cnt++;
        length=sendto(socked,buf,strlen(buf),0,(struct sockaddr *)&remote_addr,sizeof(remote_addr));
        printf("Send Message:%s\t, cnt:%d\n", buf, cnt);
        sleep(1);
    }
    close(socked);
    return 0;
}


接收程序代码:

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc,char *argv[]){
    int socked=socket(AF_INET,SOCK_DGRAM,0);
    if(socked<0)
    {
        perror("socket failed!");
        return 2;
    }

    int reuse = 1;
    if (setsockopt(socked, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) {
        perror("Failed to set SO_REUSEADDR option \n");
        return 1;
    }

    char group[16]="239.255.0.1";
    struct sockaddr_in local_addr;
    memset(&local_addr,0,sizeof(local_addr));
    local_addr.sin_family = AF_INET;
    local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    local_addr.sin_port = htons(5000);

    int ret = bind(socked, (struct sockaddr*)&local_addr, sizeof(local_addr));
    if(ret<0)
    {
        perror("bind failed !");
        return 3;
    }



    struct ip_mreq mreq;
    mreq.imr_multiaddr.s_addr = inet_addr(group);
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
    /*
     *
     *  int setsockopt(int sockfd, int level, int optname,
                      const void *optval, socklen_t optlen);
     * param:
     *      optname
     *          * IP_MULTICAST_LOOP 支持多播数据回送
     *          * IP_ADD_MEMBERSHIP 加入多播组
     *          * IP_DROP_MEMBERSHIP 离开多播组
     *      optval
     *          * IP_MULTICAST_LOOP 选项对应传入 unsigned int 来确认是否支持多播数据回送
     *          * IP_ADD_MEMBERSHIP 传入 ip_mreq
     *          * IP_DROP_MEMBERSHIP 传入 ip_mreq
     *
     * */
    ret=setsockopt(socked,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));
    if(ret<0){
        perror("setsockopt failed !");
        return 3;
    }else
    {
        printf("setsockopt success\n");
    }


    char buf[1024];
    int length=0;
    struct sockaddr_in sender;
    socklen_t sender_len=sizeof(sender);
    uint32_t cnt=0;
    while (true){
        cnt++;
        memset(buf, 0, sizeof(buf));
        length=recvfrom(socked, buf, sizeof(buf), 0, (struct sockaddr*)&sender,&sender_len);
        buf[length]='\0';
        printf("%s %d : %s\t, cnt:%d\n",inet_ntoa(sender.sin_addr),ntohs(sender.sin_port),buf, cnt);
        // sleep(1);
    }
    setsockopt(socked, IPPROTO_IP, IP_DROP_MEMBERSHIP,&mreq, sizeof(mreq));
    close(socked);
    return 0;
}

 

 

  • 14
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

踏马潜行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值