目录

一、UDP组播介绍

1.UDP介绍        

2.UDP组播

3.组播地址

4.组播的原理:

二、UDP组播编程

1.UDP组播的基本步骤

2.加入组播组-setsockopt

三、UDP组播服务端代码实现

 1.代码实现

2.运行结果

四、UDP单播客户端代码实现 

 1.代码实现

2.运行结果


一、UDP组播介绍

1.UDP介绍        

        UDP协议进行信息的传输之前不需要建议连接。换句话说就是客户端向服务器发送信息,客户端只需要给出服务器的ip地址和端口号,然后将信息封装到一个待发送的报文中并且发送出去。至于服务器端是否存在,或者能否收到该报文,客户端根本不用管。更多UDP详细介绍可以查看:Linux网络编程-UDP协议详解

2.UDP组播

        组播是一对多的传输方式,其中有个组播组的概念,发送端将数据向一个组内发送,网络中的路由器通过底层的IGMP协议自动将数据发送到所有监听这个组的终端。至于广播则和组播有一些相似,区别是路由器向子网内的每一个终端都投递一份数据包,不论这些终端是否乐于接收该数据包。UDP广播只能在内网(同一网段)有效,而组播可以较好实现跨网段群发数据。

       UDP组播是采用的无连接,数据报的连接方式,所以是不可靠的。也就是数据能不能到达接受端和数据到达的顺序都是不能保证的。但是由于UDP不用保证数据 的可靠性,所有数据的传送效率是很快的。

        然而在ip组播环中,数据包的目的地址不是一个,而是一组,形成组地址。所有的信息接收者都加入到一个组内,并且一旦加入之后,流向组地址的数据立即开始向接收者传输,组中的所有成员都能接收到数据包。组播组中的成员是动态的,主机可以在任何时刻加入和离开组播组。

        用同一个IP多播地址接收多播数据包的所有主机构成了一个主机组,也称为多播组。一个多播组的成员是随时变动的,一台主机可以随时加入或离开多播组,多播组成员的数目和所在的地理位置也不受限制,一台主机也可以属于几个多播组。此外,不属于某一个多播组的主机也可以向该多播组发送数据包。  



3.组播地址

        组播组可以是永久的也可以是临时的,组播组地址中,有一部分由官方分配的,称为永久组播组。永久组播组保持不变的是它的ip地址,组中的成员构成可以发生变化。永久​​​​​​​组播组中成员的数量都可以是任意的,甚至可以为零。那些没有保留下来供永久​​​​​​​组播组使用的ip组播地址,可以被临时组播组利用。

                IP地址
244.0.0.0~244.0.0.255局部链接多播地址:是为路由协议和其它用途保留的地址,路由器并不转发属于此范围的IP包
244.0.1.0~244.0.1.255预留多播地址:公用组播地址,可用于Internet;使用前需要申请
244.0.2.0~238.255.255.255预留多播地址:用户可用组播地址(临时组地址),全网范围内有效
239.0.0.0~239.255.255.255本地管理组播地址,可供组织内部使用,类似于私有 IP 地址,不能用于 Internet,可限制多播范围



4.组播的原理:

      组播首先由一个用户申请一个组播组,这个组播组被维护在路由器中,其他用户申请加入组播组,这样当一个用户向组内发送消息时,路由器将消息转发给组内的所有成员。如果申请加入的组不在本级路由中,如果路由器和交换机允许组播协议通过,路由器将申请加入的操作向上级路由提交。广域网通信要经过多级路由器和交换机,几乎所有的网络设备都默认阻止组播协议通过(只允许本网段内,不向上级提交),这使得广域网上实现组播有一定局限。

二、UDP组播编程

    UDP组播相对于单播而言,多了一个加入组播组的过程,这里只对加入组播组函数说明,其他函数可以查看博主文章:Linux网络编程-UDP单播_ProYuan的博客-CSDN博客

1.UDP组播的基本步骤

  1. 建立socket
  2. socket和端口绑定
  3. 加入一个组播组
  4. 通过sendto / recvfrom进行数据的收发
  5. 关闭socket

2.加入组播组-setsockopt

        int setsockopt(int sockfd, int level,int optname,const void *optval, socklen_t optlen);

返回值:成功执行返回0,否则返回-1

三、UDP组播服务端代码实现

 1.代码实现

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

#define BUF_SIZE 		88
#define PORT     		55555
#define ADDR     		"192.168.111.213"
#define MUNICASTADDR    "236.9.9.9"

int main(int argc, char *argv[])
{
    //建立套接字
    int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);           //IPV4,数据报套接字类型,不指定协议

    //说明本服务器地址
    struct sockaddr_in srvaddr;
	srvaddr.sin_family = AF_INET,                              //协议类型IPV4
	srvaddr.sin_port = htons(PORT),                            //端口号-网络字节序
	srvaddr.sin_addr.s_addr = htonl(INADDR_ANY);                //IP地址-任意地址

    //绑定地址
    bind(sock_fd, (const struct sockaddr *)&srvaddr, sizeof(srvaddr));
	
	srvaddr.sin_addr.s_addr = inet_addr(ADDR);
	setsockopt(sock_fd, IPPROTO_IP, IP_MULTICAST_IF, (void*)&srvaddr,sizeof(struct sockaddr_in));

	struct ip_mreq	ipMreq;
	ipMreq.imr_interface.s_addr = inet_addr(ADDR);
	ipMreq.imr_multiaddr.s_addr = inet_addr(MUNICASTADDR);

    //接收数据
    char buf[BUF_SIZE] = { 0 };
    struct sockaddr_in cliaddr;
    socklen_t cliaddrlen = sizeof(cliaddr);
    while (1)
    {
        bzero(buf, BUF_SIZE);
        bzero(&cliaddr, cliaddrlen);
        recvfrom(sock_fd, buf, BUF_SIZE, 0, (struct sockaddr *)&cliaddr, &cliaddrlen);
        printf("udp server from [%s - %hu]:%s\n",inet_ntoa(cliaddr.sin_addr),cliaddr.sin_port,buf);
    }

    //关闭套接字
    close(sock_fd);

    return 0;
}

2.运行结果

四、UDP单播客户端代码实现 

 1.代码实现

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

#define BUF_SIZE 		88
#define PROT     		55555
#define ADDR     		"192.168.111.213"
#define MUNICASTADDR    "236.9.9.9"

int main(int argc, char *argv[])
{
    //建立套接字
    int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);           //IPV4,数据报套接字类型,不指定协议

    //声明将连接地址
    struct sockaddr_in  srvaddr;
	srvaddr.sin_family = AF_INET,                              //协议类型IPV4
	srvaddr.sin_port = htons(PROT),                            //端口号-网络字节序
	srvaddr.sin_addr.s_addr = inet_addr(ADDR);                 //IP地址-字符串转IP

	
	struct ip_mreq	ipMreq;
	setsockopt(sock_fd, IPPROTO_IP, IP_MULTICAST_IF, (void*)&srvaddr,
		sizeof(struct sockaddr_in));
	ipMreq.imr_interface.s_addr = inet_addr(ADDR);
	ipMreq.imr_multiaddr.s_addr = inet_addr(MUNICASTADDR);
	setsockopt(sock_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &ipMreq, sizeof(ipMreq));

    //发送数据
    char buf[BUF_SIZE] = { 0 };
	int count = 0;
    while (1)
    {
        memset(buf,0, BUF_SIZE);
        sprintf(buf, "%d",count);
		printf("udp client send:[%s - %d]:%s\n",ADDR,PROT,buf);
        sendto(sock_fd, buf, strlen(buf), 0, (const struct sockaddr*)&srvaddr, sizeof(srvaddr));
		count++;
		sleep(1);
    }

    //关闭套接字
    close(sock_fd);

    return 0;
}

2.运行结果

更多推荐

Linux网络编程-UDP组播服务客户端代码实现