嵌入式开发第36天(UDP网络传输之:广播、组网原理)



广播

1.定义

前面介绍的数据包发送方式只有一个接受方,称为单播。

如果同时发给局域网中的所有主机,称为广播

只有用户数据报(使用UDP协议)套接字才能广播


2.广播地址

  以192.168.1.x网段为例,最大的主机地址192.168.1.255代表该网段的广播地址


3.初始化套接字注意事项



a.创建用户数据报套接字

缺省创建的套接字不允许广播数据包,需要设置属性
setsockopt可以设置套接字属性


b.接收方地址指定为广播地址


192.168.1.255   // 只能接收该网段的广播数据
0.0.0.0 // 既可以接收单播、广播、组播


4.setsockopt函数

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

头文件:<sys/socket.h>

level : 选项级别(例如SOL_SOCKET)

optname : 选项名(例如SO_BROADCAST)

optval : 存放选项值的缓冲区的地址
optlen : 缓冲区长度
返回值:成功返回 0   
       失败返回    -1并设置errno


组播(多播)

1.定义


广播方式发给所有的主机。过多的广播会大量占用网络带宽,造成广播风暴,影响正常的通信。

组播(又称为多播)是一种折中的方式。只有加入某个多播组的主机才能收到数据。
多播方式既可以发给多个主机,又能避免象广播那样带来过多的负载(每台主机要到传输层才能判断广播包是否要处理)


2.地址
D类地址(组播地址)
范围:
224.0.0.1 – 239.255.255.255


3.发送方与接收方的设置


A.发送方

1)创建用户数据报套接字
2)发送数据的时候指定接收方地址为组播地址
3)指定端口信息
4)数据收发

B.接收方

1)创建用户数据报套接字
2)加入组播
3)绑定
4)数据收发


广播例子

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>

void *thread_udp_recv(void *parg)
{
	int socket_fd = (int)parg;
	int len,addr_len;
	
	char recv_buf[1500];
	
	struct sockaddr_in dest_addr;
	
	printf("thread_udp_recv in running....\n");

	while(1)
	{
		/* 接收前清空recvbuf */
		bzero(recv_buf,sizeof recv_buf);
		
		addr_len = sizeof dest_addr;
		
		bzero(recv_buf,sizeof recv_buf);
		
		len = recvfrom(socket_fd,recv_buf,sizeof recv_buf,0,(struct sockaddr *)&dest_addr,&addr_len);
		
		if(len <= 0)
		{
			perror("recv fail:");
			
			break;
		}
		
		char *p = inet_ntoa(dest_addr.sin_addr);
					
		printf("dest_info = [ip]%s,[port]%d \n",p, ntohs (dest_addr.sin_port)) ;			
		
		
		
	}
}

int main(int argc, char **argv)
{
	int socket_fd;
	int rt;
	int len;
	
	struct sockaddr_in local_addr,dest_addr;
	
	/* 创建套接字,类型为UDP协议 */
	socket_fd = socket(AF_INET,SOCK_DGRAM,0);
	
	if(socket_fd < 0)
	{
		perror("creaet socket for udp fail");
		
		return -1;
	}
	
	/* 设置本地IP地址与端口属性 */
	local_addr.sin_family 		= AF_INET;						//IPv4
	local_addr.sin_port   		= htons(16888);					//接收数据端口
	local_addr.sin_addr.s_addr 	= inet_addr("192.168.1.205" );	//设置为自己的IP地址,只接收单播数据

	int on=1;
	/* 设置socket允许重复使用地址与端口,SO_REUSEADDR值为2 */
	setsockopt(socket_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof on);
	

	/* 使能广播功能,SO_BROADCAST值为6 */
	on=1;
	setsockopt(socket_fd,SOL_SOCKET,SO_BROADCAST,&on,sizeof on);

	
	/* 进行绑定端口与地址 */
	//把套接字和自身的信息绑定在一起 
	
	len = sizeof local_addr;
	
	rt = bind(socket_fd ,(struct sockaddr*)&local_addr, len );
	
	if (rt == -1)
	{
		perror("bind failed");
		
		return -1;
	}	
	
	/* 设置本地IP地址与端口属性 */
	dest_addr.sin_family 		= AF_INET;		//IPv4
	dest_addr.sin_port   		= htons(16888);	//接收数据端口
	dest_addr.sin_addr.s_addr 	= inet_addr("192.168.1.255" );//设置目的IP地址为广播地址 192.168.1.255代表该网段的广播地址
	
	
	pthread_t tid;
	
	/* 创建接收线程,用于处理文字信息与文件收发,并传入socket_fd到线程当中 */
	pthread_create(&tid,NULL,&thread_udp_recv,(void *)socket_fd);

	
	while(1)
	{
		
		len = sendto(socket_fd,"hello world",11,0,(struct sockaddr *)&dest_addr,sizeof dest_addr);
	
		if(len > 0)
		{
			printf("sendto success,len=%d\n",len);
		}
		system("clear");
		sleep(3);
	}
	
	
	return 0;
}


组播例子 

send.c

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>


int main(int argc, char **argv)
{
	int socket_fd;
	int rt;
	int len;
	
	struct sockaddr_in local_addr,dest_addr;
	
	/* 创建套接字,类型为UDP协议 */
	socket_fd = socket(AF_INET,SOCK_DGRAM,0);
	
	if(socket_fd < 0)
	{
		perror("creaet socket for udp fail");
		
		return -1;
	}
	
	/* 设置本地IP地址与端口属性 */
	local_addr.sin_family 		= AF_INET;						//IPv4
	local_addr.sin_port   		= htons(16888);					//接收数据端口
	local_addr.sin_addr.s_addr 	= inet_addr("192.168.1.5" );	//设置为自己的IP地址,只接收单播数据

	int on=1;
	
	/* 设置socket允许重复使用地址与端口,SO_REUSEADDR值为2 */
	setsockopt(socket_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof on);
	

	
	/* 进行绑定端口与地址 */
	//把套接字和自身的信息绑定在一起 
	len = sizeof local_addr;
	
	rt = bind(socket_fd ,(struct sockaddr*)&local_addr, len );
	
	if (rt == -1)
	{
		perror("bind failed");
		
		return -1;
	}	
	
	/* 设置本地IP地址与端口属性 */
	dest_addr.sin_family 		= AF_INET;					//IPv4
	dest_addr.sin_port   		= htons(16888);				//接收数据端口
	dest_addr.sin_addr.s_addr 	= inet_addr("224.10.10.1" );//设置目的IP地址为组播地址
	
	
	while(1)
	{
		
		len = sendto(socket_fd,"hello world",11,0,(struct sockaddr *)&dest_addr,sizeof dest_addr);
	
		if(len > 0)
		{
			printf("sendto success,len=%d\n",len);
		}

		sleep(3);
	}
	
	
	return 0;
}




接收recv.c
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
	int socket_fd;
	int rt;
	int len,addr_len;
	char recv_buf[1024]={0};
	
	struct sockaddr_in local_addr,dest_addr;
	
	/* 创建套接字,类型为UDP协议 */
	socket_fd = socket(AF_INET,SOCK_DGRAM,0);
	
	if(socket_fd < 0)
	{
		perror("creaet socket for udp fail");
		
		return -1;
	}
	
	struct ip_mreq mreq;
	
	bzero(&mreq,sizeof mreq);
	
	mreq.imr_multiaddr.s_addr = inet_addr("224.10.10.1");	//设置当前的组播地址
	mreq.imr_interface.s_addr = inet_addr("0.0.0.0");		//将系统的IP对应的网卡接口加入到组播		
	
	/* 加入组播 */
	setsockopt(socket_fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof mreq);

	
	/* 设置本地IP地址与端口属性 */
	local_addr.sin_family 		= AF_INET;				//IPv4
	local_addr.sin_port   		= htons(16888);			//接收数据端口
	local_addr.sin_addr.s_addr 	= inet_addr("0.0.0.0" );//设置当前系统能够接收单播,组播,广播信息

	int on=1;
	/* 设置socket允许重复使用地址与端口,SO_REUSEADDR值为2 */
	setsockopt(socket_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof on);	
	
	/* 进行绑定端口与地址 */
	//把套接字和自身的信息绑定在一起 
	
	len = sizeof local_addr;
	
	rt = bind(socket_fd ,(struct sockaddr*)&local_addr, len );
	
	if (rt == -1)
	{
		perror("bind failed");
		
		return -1;
	}	
	
	
	
	while(1)
	{
		addr_len = sizeof dest_addr;
		
		bzero(recv_buf,sizeof recv_buf);
		
		len = recvfrom(socket_fd,recv_buf,sizeof recv_buf,0,(struct sockaddr *)&dest_addr,&addr_len);
	
		if(len > 0)
		{
			char *p = inet_ntoa(dest_addr.sin_addr);
					
			printf("dest_info = [ip]%s,[port]%d \n",p, ntohs (dest_addr.sin_port)) ;			
			printf("recvfrom len =%d\n",len);
			printf("recvfrom data=%s\n\n",recv_buf);
			
			/* 将接收到信息进行重发 */
			sendto(socket_fd,recv_buf,len,0,(struct sockaddr *)&dest_addr,sizeof dest_addr);
		}

	}
	
	
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

交叉编译之王 hahaha

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

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

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

打赏作者

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

抵扣说明:

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

余额充值