广播与组播

目录

  • 一、广播
    • 1. 什么是广播?
    • 2. 广播的实现
  • 二、组播
    • 1. 分类的IP地址
    • 2. 多播IP地址
    • 3. 组播的实现

广播与组播和实现UDP通信的代码差不多

一、广播

1. 什么是广播?

数据包发送方式只有一个接受方,称为单播
如果同时发给局域网中的所有主机,称为广播
只有用户数据报(使用UDP协议)套接字才能广播
广播地址
   一个网络内主机号全为1的IP地址为广播地址
   发到该地址的数据包被所有的主机接收
   255.255.255.255在所有网段中都代表广播地址

2. 广播的实现

广播与组播_第1张图片

int on = 1;
setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));

实现代码:
receiver.c

#include 
#include 
#include 
#include  /* superset of previous */
#include 
#include 
#include 
#include 

#define ErrExit(msg) do {perror(msg); exit(EXIT_FAILURE);} while(0)
typedef struct sockaddr Addr;
typedef struct sockaddr_in Addr_in;

int main(int argc, char *argv[])
{
	int fd = -1;
	Addr_in myaddr, peeraddr;
	socklen_t peerlen = sizeof(peeraddr);
	char buf[BUFSIZ] = {};
	/*参数检查*/
	if(argc < 3){
		fprintf(stderr, "%s", argv[0]);
		exit(EXIT_FAILURE);
	}
	/*创建套接字*/
	if( (fd = socket(AF_INET, SOCK_DGRAM, 0) ) < 0)
			ErrExit("socket");
	/*设置通信结构体*/
	myaddr.sin_family = AF_INET;
	myaddr.sin_port = htons(atoi(argv[2]));
	if(!inet_aton(argv[1], &myaddr.sin_addr) ){
		fprintf(stderr, "Invalid address\n");
		exit(EXIT_FAILURE);
	}
	/*绑定通信结构体*/
	if( bind(fd, (Addr *)&myaddr, sizeof(Addr_in)) )
		ErrExit("bind");
	while(1){
		recvfrom(fd, buf, BUFSIZ, 0, (Addr *)&peeraddr, &peerlen);
		printf("[%s:%d]%s\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port), buf);
	}
	return 0;
}

sender.c

#include 
#include 
#include 
#include  /* superset of previous */
#include 
#include 
#include 
#include 
#include 

#define ErrExit(msg) do {perror(msg); exit(EXIT_FAILURE);} while(0)
typedef struct sockaddr Addr;
typedef struct sockaddr_in Addr_in;

int main(int argc, char *argv[])
{
	int fd = -1;
	Addr_in peeraddr;
	socklen_t peerlen = sizeof(peeraddr);
	char buf[BUFSIZ] = {};
	/*参数检查*/
	if(argc < 3){
		fprintf(stderr, "%s", argv[0]);
		exit(EXIT_FAILURE);
	}
	/*创建套接字*/
	if( (fd = socket(AF_INET, SOCK_DGRAM, 0) ) < 0)
		ErrExit("socket");

	/*允许广播*/
	int on = 1;
	setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));

	/*设置通信结构体*/
	peeraddr.sin_family = AF_INET;
	peeraddr.sin_port = htons(atoi(argv[2]));
	if(!inet_aton(argv[1], &peeraddr.sin_addr) ){
		fprintf(stderr, "Invalid address\n");
		exit(EXIT_FAILURE);
	}
	while(1){
		fgets(buf, BUFSIZ, stdin);
		sendto(fd, buf, strlen(buf)+1, 0, (Addr *)&peeraddr, peerlen);
	}
	return 0;
}

二、组播

1. 分类的IP地址

广播与组播_第2张图片

2. 多播IP地址

  1. 在 IP 多播数据报的目的地址需要写入多播组的标识符。

  2. 多播组的标识符就是 IP 地址中的 D 类地址(多播地址)。
    地址范围:224.0.0.0 ~ 239.255.255.255

  3. 每一个 D 类地址标志一个多播组。

  4. 多播地址只能用于目的地址,不能用于源地址

3. 组播的实现

  1. 床架用户数据报套接字
  2. 加入多播组
  3. 绑定组播IP地址和端口
  4. 等待接收数据
struct ip_mreqn {
    struct in_addr imr_multiaddr;  /*IP 组播组地址*/
    struct in_addr imr_address;   /*本地接口的IP地址,用于绑定到特定的网络接口*/
    int    imr_ifindex;   /*本地网卡的编号,用于指定数据报要发送到哪个网络接口*/
}
/*imr_ifindex 成员可以指定具体的网络接口,而不是仅仅依赖于 IP 地址来确定网络接口*/
if(setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0){
perror("setsockopt");
exit(0);
}
struct ip_mreq {
    struct in_addr imr_multiaddr;  /*IP 组播组地址*/
    struct in_addr imr_interface;   /*本地接口的IP地址*/
}
/*imr_interface 成员只能指定一个具体的 IP 地址,而不能指定具体的网络接口*/
if(setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0){
perror("setsockopt");
exit(0);
}

实现代码

server.c

#include 
#include 
#include 
#include  /* superset of previous */
#include 
#include 
#include 
#include 

#define ErrExit(msg) do {perror(msg); exit(EXIT_FAILURE);} while(0)
typedef struct sockaddr Addr;
typedef struct sockaddr_in Addr_in;

int main(int argc, char *argv[])
{
	int fd = -1;
	Addr_in myaddr, peeraddr;
	socklen_t peerlen = sizeof(peeraddr);
	struct ip_mreqn mreq;
	char buf[BUFSIZ] = {};
	/*参数检查*/
	if(argc < 3){
		fprintf(stderr, "%s", argv[0]);
		exit(EXIT_FAILURE);
	}
	/*创建套接字*/
	if( (fd = socket(AF_INET, SOCK_DGRAM, 0) ) < 0)
			ErrExit("socket");
	/*加入多播组*/
	bzero(&mreq, sizeof(mreq) );
	if(!inet_aton(argv[1], &mreq.imr_multiaddr) ){
		fprintf(stderr, "Invalid address\n");
		exit(EXIT_FAILURE);
	}
	if(setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0){
		perror("setsockopt");
		exit(0);
	}

	/*设置通信结构体*/
	myaddr.sin_family = AF_INET;
	myaddr.sin_port = htons(atoi(argv[2]));
	if(!inet_aton(argv[1], &myaddr.sin_addr) ){
		fprintf(stderr, "Invalid address\n");
		exit(EXIT_FAILURE);
	}
	/*绑定通信结构体*/
	if( bind(fd, (Addr *)&myaddr, sizeof(Addr_in)) )
		ErrExit("bind");
	while(1){
		recvfrom(fd, buf, BUFSIZ, 0, (Addr *)&peeraddr, &peerlen);
		printf("[%s:%d]%s\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port), buf);
	}
	return 0;
}

client.c

#include 
#include 
#include 
#include  /* superset of previous */
#include 
#include 
#include 
#include 
#include 

#define ErrExit(msg) do {perror(msg); exit(EXIT_FAILURE);} while(0)
typedef struct sockaddr Addr;
typedef struct sockaddr_in Addr_in;

int main(int argc, char *argv[])
{
	int fd = -1;
	Addr_in peeraddr;
	socklen_t peerlen = sizeof(peeraddr);
	char buf[BUFSIZ] = {};
	/*参数检查*/
	if(argc < 3){
		fprintf(stderr, "%s", argv[0]);
		exit(EXIT_FAILURE);
	}
	/*创建套接字*/
	if( (fd = socket(AF_INET, SOCK_DGRAM, 0) ) < 0)
		ErrExit("socket");

	/*设置通信结构体*/
	peeraddr.sin_family = AF_INET;
	peeraddr.sin_port = htons(atoi(argv[2]));
	if(!inet_aton(argv[1], &peeraddr.sin_addr) ){
		fprintf(stderr, "Invalid address\n");
		exit(EXIT_FAILURE);
	}
	while(1){
		fgets(buf, BUFSIZ, stdin);
		sendto(fd, buf, strlen(buf)+1, 0, (Addr *)&peeraddr, peerlen);
	}
	return 0;
}

运行结果
广播与组播_第3张图片

你可能感兴趣的:(单片机,嵌入式硬件)