udp组播demo

udp组播

组播报文的目的地址使用D类IP地址, D类地址不能出现在IP报文的源IP地址字段。单播数据传输过程中,一个数据包传输的路径是从源地址路由到目的地址,利用“逐跳”的原理[路由选择]在IP网络中传输。

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

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

组播地址

组播组可以是永久的也可以是临时的。组播组地址中,有一部分由官方分配的,称为永久组播组。永久组播组保持不变的是它的ip地址,组中的成员构成可以发生变化。永久组播组中成员的数量都可以是任意的,甚至可以为零。那些没有保留下来供永久组播组使用的ip组播地址,可以被临时组播组利用。
224.0.0.0~224.0.0.255为预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其它地址供路由协议使用;
224.0.1.0~224.0.1.255是公用组播地址,可以用于Internet;
224.0.2.0~238.255.255.255为用户可用的组播地址(临时组地址),全网范围内有效;
239.0.0.0~239.255.255.255为本地管理组播地址,仅在特定的本地范围内有效。
组播是一对多的传输方式,其中有个组播组的 概念,发送端将数据向一个组内发送,网络中的路由器通过底层的IGMP协议自动将数据发送到所有监听这个组的终端。至于广播则和组播有一些相似,区别是路由器向子网内的每一个终端都投递一份数据包,不论这些终端是否乐于接收该数据包。UDP广播只能在内网(同一网段)有效,而组播可以较好实现跨网段群发数据。

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

组播的原理

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

UDP组播的基本步骤

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

如何加入一个组
struct ip_mreq mreq;

mreq.imr_multiaddr.s_addr  组播IP地址  230.1.1.1
mreq.imr_interface.s_addr  IP地址      监听IP地址  

udp组播接收/发送demo

udp_group_rcv.c(接收端)demo:

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

#define BUFLEN 255

int main(int argc, char **argv)
{
	struct sockaddr_in peeraddr;
	struct in_addr ia;
	int sockfd;
	char recmsg[BUFLEN + 1];
	unsigned int socklen, n;
	struct hostent *group;
	struct ip_mreq mreq;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) 
	{
		printf("socket creating err in udptalk\n");
		exit(EXIT_FAILURE);
	}


	bzero(&mreq, sizeof(struct ip_mreq));
	if (argv[1]) 
	{
		if ((group = gethostbyname(argv[1])) == (struct hostent *) 0) 
		{
			perror("gethostbyname");
			exit(EXIT_FAILURE);
		}
	} 
	else 
	{
		printf("you should give me a group address, 224.0.0.0-239.255.255.255\n");
		exit(EXIT_FAILURE);
	}

	bcopy((void *) group->h_addr, (void *) &ia, group->h_length);
	
	bcopy(&ia, &mreq.imr_multiaddr.s_addr, sizeof(struct in_addr));

	
	//mreq.imr_interface.s_addr = htonl(INADDR_ANY);
	if (argv[2]) {
		if (inet_pton(AF_INET, argv[2], &mreq.imr_interface.s_addr) <= 0) 
		{	
			printf("Wrong dest IP address!\n");
			exit(EXIT_FAILURE);
		}
	} 

	
	if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,sizeof(struct ip_mreq)) == -1) 
	{
		perror("setsockopt");
		exit(EXIT_FAILURE);
	}

	socklen = sizeof(struct sockaddr_in);
	memset(&peeraddr, 0, socklen);
	peeraddr.sin_family = AF_INET;
	peeraddr.sin_port = htons(7838);
	
	if (argv[1]) {
		if (inet_pton(AF_INET, argv[1], &peeraddr.sin_addr) <= 0) 
		{	
			printf("Wrong dest IP address!\n");
			exit(EXIT_FAILURE);
		}
	} 
	else 
	{
		printf("no group address given, 224.0.0.0-239.255.255.255\n");
		exit(EXIT_FAILURE);
	}


	if (bind(sockfd, (struct sockaddr *) &peeraddr,sizeof(struct sockaddr_in)) == -1) 
	{
		printf("Bind error\n");
		exit(EXIT_FAILURE);
	}


	for (;;) 
	{
		bzero(recmsg, BUFLEN + 1);
		n = recvfrom(sockfd, recmsg, BUFLEN, 0,(struct sockaddr *) &peeraddr, &socklen);
		if (n < 0) 
		{
			printf("recvfrom err in udptalk!\n");
			exit(EXIT_FAILURE);
		} 
		else 
		{

			recmsg[n] = 0;
			printf("peer:%s", recmsg);
		}
	}
} 

udp_group_send.c(发送端)demo:

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFLEN 255
int main(int argc, char **argv)
{
        struct sockaddr_in peeraddr, myaddr;
        int sockfd;
        char recmsg[BUFLEN + 1];
        unsigned int socklen;
        sockfd = socket(AF_INET, SOCK_DGRAM, 0);	
        if (sockfd < 0)
        {
                printf("socket creating error\n");
                exit(EXIT_FAILURE);
        }
        socklen = sizeof(struct sockaddr_in);
        memset(&peeraddr, 0, socklen);
        peeraddr.sin_family = AF_INET;
        peeraddr.sin_port = htons(7838);		
        if (argv[1]) {					
                if (inet_pton(AF_INET, argv[1], &peeraddr.sin_addr) <= 0) {
                        printf("wrong group address!\n");
                        exit(EXIT_FAILURE);
                }
        } 
        else {
                printf("no group address!\n");
                exit(EXIT_FAILURE);
        }
        memset(&myaddr, 0, socklen);
        myaddr.sin_family = AF_INET;
        myaddr.sin_port = htons(23456);		
        if (argv[2]) {				
                if (inet_pton(AF_INET, argv[2], &myaddr.sin_addr) <= 0) 
                {
                        printf("self ip address error!\n");
                        exit(EXIT_FAILURE);
                }
        } else
                myaddr.sin_addr.s_addr = INADDR_ANY;
        if (bind(sockfd, (struct sockaddr *) &myaddr,sizeof(struct sockaddr_in)) == -1) 
        {								
                printf("Bind error\n");
                exit(EXIT_FAILURE);
        }
        for (;;) {
                bzero(recmsg, BUFLEN + 1);
                printf("input message to send:");
                if (fgets(recmsg, BUFLEN, stdin) == (char *) EOF)	
                        exit(EXIT_FAILURE);;
                if (sendto(sockfd, recmsg, strlen(recmsg), 0,(struct sockaddr *) &peeraddr,
						sizeof(struct sockaddr_in)) < 0) 			
                {
                        printf("sendto error!\n");
                       exit(EXIT_FAILURE);;
                }
                printf("sned message:%s", recmsg);	
        }
}

编译

gcc udp_group_rcv.c -o udp_group_rcv
gcc udp_group_send.c -o udp_group_send

运行

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_45309916/article/details/107387098
今日推荐