单播、多播(组播)、广播

2018-08-19 11:41:11

单播

单播在网络中得到了广泛的应用。网络上绝大部分的数据都是以单播的形式传输的,仅仅是一般网络用户不知道而已。比如浏览网页,发送邮件等。一般会称为点对点通信。

组播

主机之间 一对多 的通讯模式。一个用户向一个组发送数据,所有加入这个组的主机都能收到数据。

主机可以向路由器请求加入或退出某个组,网络中的路由器和交换机有选择的复制并传输数据,即只将组内数据传输给那些加入组的主机。这样既能一次将数据传输给多个有需要(加入组)的主机,又能保证不影响其他不需要(未加入组)的主机的其他通讯。 

多播的ip地址为D类地址范围是 224.0.0.0/4 即 224.0.0.0 - 239.255.255.255。

局部多播地址:在224.0.0.0~224.0.0.255之间,这是为路由协议和其他用途保留的地址,路由器并不转发属于此范围的IP包。

预留多播地址:在224.0.1.0~238.255.255.255 之间,可用于全球范围(如Internet)或网络协议。

管理权限多播地址:在239.0.0.0~239.255.255.255之间,可供组织内部使用,类似于私有IP地址,不能用于Internet,可限制多播范围。

加入多播组

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
 
int main(int argc, char*argv[])  
{     
	int sockfd; // 套接字文件描述符  
	struct sockaddr_in local_addr; // 本地地址 
	int err = -1; 
	char group[16] = "224.0.0.88"; // 多播组 IP
	  
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);  //建立套接字
	if (sockfd == -1)  
	{  
		perror("socket()");  
		return -1;  
	}     
	  
	// 初始化地址 
	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(8000);
	  
	// 绑定socket  
	err = bind(sockfd,(struct sockaddr*)&local_addr, sizeof(local_addr));  
	if(err < 0)  
	{  
		perror("bind()");  
		return -2;  
	}    
 
	struct ip_mreq mreq; // 多播地址结构体                                 
 
	// 加入多播组,相当于创建一个QQ群,某人加入此群
	mreq.imr_multiaddr.s_addr = inet_addr(group); // 多播地址,类似于 QQ 群号 
	mreq.imr_interface.s_addr = htonl(INADDR_ANY);// 将本机加入多播组,类似于某人加入此群
	// 加入多播组
	err = setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,&mreq, sizeof(mreq));  
	if (err < 0)  
	{  
		perror("setsockopt():IP_ADD_MEMBERSHIP");  
		return -4;  
	}  
 
	int times = 0;  
	int addr_len = 0;  
	char buff[256] = {0};  
	int n = 0; 
 
	// 循环接收广播组的消息,5次后退出
	for(times = 0; times<5; times++)  
	{  
		addr_len = sizeof(local_addr);  
		memset(buff, 0, sizeof(buff));     
		
		// 接收数据 
		n = recvfrom(sockfd, buff, sizeof(buff), 0,(struct sockaddr*)&local_addr, &addr_len);  
		if( n== -1)   
		{  
			perror("recvfrom()");  
		}  
 
		printf("Recv %dst message from server:%s\n", times, buff);  
		sleep(2);   
	}  
	  
	// 退出广播组 
	err = setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP,&mreq, sizeof(mreq));  
		  
	close(sockfd); 
 
	return 0;  
}

发送多播

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
 
int main(int argc, char*argv)
{
	int sockfd; // 套接字文件描述符
	struct sockaddr_in dest_addr; // 目标ip
	char buf[] = "BROADCAST TEST DATA";
 
	sockfd = socket(AF_INET, SOCK_DGRAM, 0); // 建立套接字
 
	// 初始化目标 ip 信息
	memset(&dest_addr, 0, sizeof(dest_addr));
	dest_addr.sin_family = AF_INET;               
	dest_addr.sin_addr.s_addr = inet_addr("224.0.0.88"); // 目的地址,为多播地址
	dest_addr.sin_port = htons(8000); 	// 多播服务器的端口也是 8000
 
	// 向多播地址发送数据
	while(1){
		int n = sendto(sockfd, buf, strlen(buf), 0,(struct sockaddr*)&dest_addr, sizeof(dest_addr));
		if( n < 0)
		{
			perror("sendto()");
			return -2;
		}      
 
		sleep(1);
	}
 
	return 0;
}


广播

广播存在的目的是通知局域网内所有的主机。0.0.0.0 为保留的广播源地址。

广播分为两类:受限广播和直接广播

受限广播:路由器从来不会转发受限广播的数据包,但同一个子网的所有主机都会接收到受限广播的数据包,受限广播的目的ip地址为 255.255.255.255。

直接广播:可以被路由转发,发送到目标网络的所有主机,如 ip地址为 192.168.2.1 的主机也可以发送广播到 192.168.1.0 这个网络,即发送数据包到 192.168.1.255。通常路由器是默认阻止直接广播的(可以设置不阻止)。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
 
int main(int argc, char *argv[])
{
	unsigned short port = 8000;				// 端口
	char *server_ip = "255.255.255.255";	// 受限广播地址
 
	int sockfd;
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);    	//创建UDP套接字
	if(sockfd < 0)
	{
		perror("socket");
		exit(-1);
	}
	
	struct sockaddr_in dest_addr;
	bzero(&dest_addr, sizeof(dest_addr));
	dest_addr.sin_family = AF_INET;
	dest_addr.sin_port   = htons(port);
	inet_pton(AF_INET, server_ip, &dest_addr.sin_addr);
 
	printf("send data to UDP server %s:%d!\n", server_ip, port);
	
	//设置该套接字为广播类型,这个很重要
	int opt=1;
	setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt));
	
	char send_buf[512] = "this is a broadcast data";
	sendto(sockfd, send_buf, strlen(send_buf), 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr));//发送数据
 
	close(sockfd);
	
	return 0;
}


©著作权归作者所有
收藏
推荐阅读
简介
天降大任于斯人也,必先苦其心志。