- 组播概念
单播方式只能发给一个接收方。
广播方式发给所有的主机。过多的广播会大量占用网络带宽,造成广播风暴,影响正常的通信。
组播(又称为多播)是一种折中的方式。只有加入某个多播组的主机才能收到数据。
多播方式既可以发给多个主机,又能避免象广播那样带来过多的负载(每台主机要到传输层才能判断广播包是否要处理) - 组播地址段
D类地址(组播地址)
不分网络地址和主机地址,第1字节的前4位固定为1110
224.0.0.1 – 239.255.255.255 代码流程
发送者(send):
创建套接字;
填充组播网络信息结构体;
发送消息接收者(recv):
创建套接字;
填充组播网络信心结构体;
绑定IP和端口号;
将接收者加入到多播组里面;用到的结构体
struct ip_mreq
{
/* IP multicast address of group. */
struct in_addr imr_multiaddr; //组播地址,发送者地址/* Local IP address of interface. */
struct in_addr imr_interface; //主机地址
//INADDR_ANY 任意的主机地址
};
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(argv[1]);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
发送端(send)
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
//实现组播的发送
#define N 128
#define err_log(errmsg) do{perror(errmsg); exit(1);}while(0)
int main(int argc, const char *argv[])
{
int sockfd;
struct sockaddr_in groupcastaddr;
char buf[N] = {};
if(argc < 3)
{
fprintf(stderr, "Usage: %s broadcast-ip-port.\n", argv[0]);
}
//第一步:创建套接字
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
err_log("fail to socket");
}
//第二步:填充组播信息结构体
groupcastaddr.sin_family = AF_INET;
groupcastaddr.sin_addr.s_addr = inet_addr(argv[1]);
groupcastaddr.sin_port = htons(atoi(argv[2]));
//第三步:发送数据
while(1)
{
printf("groupcast__msg >>> ");
fgets(buf, N, stdin);
buf[strlen(buf) - 1] = '\0';
if(sendto(sockfd, buf, N, 0, (struct sockaddr *)&groupcastaddr, sizeof(groupcastaddr)) < 0)
{
err_log("fail to sendto");
}
}
close(sockfd);
return 0;
}
接收端(recv)
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
//组播接收的实现
#define N 128
#define err_log(errmsg) do{perror(errmsg); exit(1);}while(0)
int main(int argc, const char *argv[])
{
int sockfd;
struct sockaddr_in groupcastaddr;
char buf[N] = {};
if(argc < 3)
{
fprintf(stderr, "Usage: %s broadcast-ip-port.\n", argv[0]);
}
//第一步:创建套接字
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
err_log("fail to socket");
}
//第二步:填充组播信息结构体
groupcastaddr.sin_family = AF_INET;
groupcastaddr.sin_addr.s_addr = inet_addr(argv[1]);
groupcastaddr.sin_port = htons(atoi(argv[2]));
//第三步:绑定套接字
if(bind(sockfd, (struct sockaddr *)&groupcastaddr, sizeof(groupcastaddr)) < 0)
{
err_log("fail to bind");
}
socklen_t addrlen = sizeof(struct sockaddr_in);
//第四步:将本机地址添加到组播组
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(argv[1]); //组播地址
mreq.imr_interface.s_addr = htonl(INADDR_ANY); //主机地址 INADDR_ANY 表示任意主机地址
//允许加入多播组
if(setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
{
err_log("fail to setsockopt");
}
//第五步:接收消息
while(1)
{
if(recvfrom(sockfd, buf, N, 0, (struct sockaddr *)&groupcastaddr, &addrlen) < 0)
{
err_log("fail to recvfrom");
}
printf("groupcast >>> %s\n", buf);
}
close(sockfd);
return 0;
}