组播简介

简介: 通过前面的文章,我们可以了解到bind系统调用的作用就是为一个本地套接口指定发送源地址和接收地址(即把一个本地套接口绑定在一个本地网络设备接口

我们还是以发送UDP的组播数据为例。其实发送一个UDP的组播数据报跟发送一个单播UDP数据报的差别并不大。

 


首先是在myudp_sendmsg函数中,如果发送接口的源地址没有确定,并且目的地址是组播地址的话,则源地址使用inet_sock->


mc_addr。而发送接口的源地址首先是通过inet_sock->saddr来确定的,如果发现inet_sock->saddr为零,


才会采用inet_sock->mc_addr的值。


通过前面的文章,我们可以了解到bind系统调用的作用就是为一个本地套接口指定发送源地址和接收地址(即把一个本地套接口绑定在一个本地网络设备接口


上)。而组播选项IP_MULTICAST_IF用于指定组播数据报的发送接口,两者的功能似乎有些重复。bind影响的是inet_sock的成员


rcv_saddr, saddr,


sport,分别表示接收地址(输入数据报首部中指定该地址为目的地址的,将被接收),发送源地址(本地某个网络设备接口的地址),发送和接收的端口。对


于单播的情况,显然rcv_saddr==saddr,因为一般来讲


,一个应用程序总是使用一个网络设备接口进行数据的收发的。但如果应用程序非要把一个组播地址和端口绑定到一个本地套接口上,则bind系统调用会让


rcv_addr=组播地址,sport=端口,而saddr等于0,但协议栈发送组播数据报必须要有一个本地网络设备接口,没有saddr,协议栈就不


知道通过那个设备发送数据报,这个任务就留给了IP_MULTICAST_IF选项,它为inet_sock的成员mc_addr和mc_index赋


值,指定本地接口用于发送组播数据报。


由上可得,如果我们的应用希望通过本地一个网络设备接口向网络发送组播数据报,而不关心接收该组的数据报(可能来自其它主机,在启动环路的情况下,也可能


是来自自己),我们可以简单地通过bind把这个发送套接字绑定到一个本地接口,然后再向组播地址发送数据报即可,但这样的话,感觉就像是自己站在组外


(不属于这个组)向组内发送数据报,源代码如下:


    #include <stdio.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include "my_inet.h"
    #include <linux/in.h>
    #define MAXBUF 256
    #define PUERTO 5000
    #define GRUPO "224.0.1.1"
    int main(void)
    {
        int fd;
        struct sockaddr_in srv,local;
        char buf[MAXBUF];
        memset( &srv, 0, sizeof(srv) );
        srv.sin_family = MY_AF_INET;
        srv.sin_port = htons(PUERTO);
        local.sin_family = AF_INET;
        local.sin_port = htons(16000);
        inet_aton("172.16.48.2", &(local.sin_addr) );
        if( inet_aton(GRUPO, &srv.sin_addr) < 0 ){
            perror("inet_aton");
            return -1;
        }
       if( (fd = socket( MY_AF_INET, SOCK_DGRAM, MY_IPPROTO_UDP) ) < 0 ){
            perror("socket");
            return -1;
        }
        if( bind( fd, (struct sockaddr *)&local, sizeof(local) ) < 0 ){
            perror("bind:");
            return -1;
        }
        while( fgets(buf, MAXBUF, stdin) ){
            if(
sendto(fd, buf, strlen(buf), 0, (struct sockaddr *)&srv,
sizeof(srv)) < 0 ){
                perror("recvfrom");
            }else{
fprintf(stdout, "Enviado a %s: %s", GRUPO, buf);
            }
        }
    }


因为bind系统调用把inet_sock的成员rcv_addr也置成了本地网络设备接口的地址172.16.48.2,所以这个程序只能发送数据报,


不能够接收到来自组224.0.1.1的数据报。如果想要发送者也能接收,应该这样改程序:


    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <string.h>
    #include <arpa/inet.h>
    #include "my_inet.h"
    #define MAXBUF 256
    #define PUERTO 5000
    #define GROUP "224.0.1.1"
    int main(void)
    {
        int fd;
        struct sockaddr_in srv,local;
        struct in_addr if_req;
        char buf[MAXBUF];
        srv.sin_family = MY_AF_INET;
        srv.sin_port = htons(PUERTO);
        inet_aton(GROUP, &srv.sin_addr);
        local.sin_family =MY_ AF_INET;
        local.sin_port = htons(16000);
        inet_aton(GROUP, &(local.sin_addr) );
        if( (fd = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP) ) < 0 ){
            perror("socket");
            return -1;
        }
        if( bind( fd, (struct sockaddr *)&local, sizeof(local) ) < 0 ){
            perror("bind:");
            return -1;
        }
        inet_aton("172.16.48.2", &(if_req) );
        if( setsockopt( fd, SOL_IP,
IP_MULTICAST_IF, &if_req, sizeof(struct in_addr) ) < 0 ){
            perror("setsockopt:");
            return -1;
        }
        while( fgets(buf, MAXBUF, stdin) ){
            if(
sendto(fd, buf, strlen(buf), 0, (struct sockaddr *)&srv,
sizeof(srv)) < 0 ){
                perror("sendto");
            }else{
fprintf(stdout, "Enviado a %s: %s", GROUP, buf);
            }
        }
    }


这回,本地套接口被绑定在了一个组播地址上了,这样,这个应用程序不仅能够发送组播数据,也能够接受同组中发往16000端口的数据报了(最好再加个


IP_ADD_MEMBERSHIP选项的操作),但bind组播地址时,只会设定接收地址为该组播地址,不会设定发送源地址,所以,必须使用


IP_MULTICAST_IF接口指定一个发送接口(程序中指定了172.16.48.2,即eth0接口)。


   这两个程序在现在的my_inet模块中均能够正常工作,但是它们调用的实际发送代码是UDP单播的代码,这基本能正常工作,但是单播的代码少了很多对组播的特殊处理,比如组播路由验证,环路发送等。


   在下一篇,我们将为模块添加组播数据报发送的代码,并给出分析。


注:严格来讲,上述两个程序都是有问题的,程序1的套接口会收到发往本机172.16.48.2接口的16000端口的数据,并阻塞在套接口的接收队列


中,程序2会收到发往组224.0.1.1的16000端口的数据,并阻塞在套接口的接收队列中。

相关文章
|
2月前
|
存储 C++ 网络架构
C++ Qt开发:QUdpSocket实现组播通信
Qt教程:使用`QUdpSocket`实现UDP组播通信。通过设置套接字选项、绑定端口、加入和离开组播组,以及发送和接收数据报,简化跨平台窗体应用开发。关键函数包括`setSocketOption`设置多播TTL,`bind`绑定地址和端口,`joinMulticastGroup`加入组播,`leaveMulticastGroup`退出,`writeDatagram`发送,和`readDatagram`接收数据报。
89 1
C++ Qt开发:QUdpSocket实现组播通信
|
7月前
|
负载均衡 网络协议 算法
计算机网络学习(八)—路由选择与协议概述
计算机网络学习(八)—路由选择与协议概述
|
网络协议
Qt网络编程之搭建Udp通信【单播、组播、广播】
Qt网络编程之搭建Udp通信【单播、组播、广播】
503 0
|
监控 网络协议
SIP协议概述
SIP协议的 全称是session-initialization-protocol,也就是会话发起协议。此篇文章以学习的方式记录下sip协议的相关内容
519 0
SIP协议概述
|
运维 前端开发 网络协议
组播基础
Multicast Server里播放视频,当成员加入组播组中也自动播放视频。
274 0
组播基础

热门文章

最新文章