单播用于两个主机之间的端对端通信。
广播用于一个主机对整个局域网上所有主机上的数据通信。
单播和广播是两个极端,要么对一个主机进行通信,要么对整个局域网上的主机进行通信。实际情况下,经常需要对一组特定的主机进行通信,而不是整个局域网上的所有主机,这就是组播的用途。
组播,也称为“多播”,将局域网中同一业务类型主机进行了逻辑上的分组,进行数据收发的时候其数据仅仅在同一分组中进行,其他的主机没有加入此分组不能收发对应的数据
MAC地址:
MAC地址(英语:Media Access Control Address),直译为媒体访问控制地址,也称为局域网地址(LAN Address),以太网地址(Ethernet Address)或物理地址(Physical Address),它是一个用来确认网络设备位置的地址。在OSI模型中,第三层网络层负责IP地址,第二层数据链接层则负责MAC地址。MAC地址用于在网络中唯一标示一个网卡,一台设备若有一或多个网卡,则每个网卡都需要并会有一个唯一的MAC地址。
格式:
MAC地址共48位(6个字节),以十六进制表示。前24位由IEEE决定如何分配,后24位由实际生产该网络设备的厂商自行指定。
ff: ff: ff: ff: ff: ff 是广播地址;
01:xx:xx:xx:xx:xx 是多播地址;
01:00:5e:xx:xx:xx 是IPv4多播地址。
1、组播IP地址范围:224.0.0.0 ~ 239.255.255.255
组播以太网地址(MAC地址):开头高三个字节是01:00:5e
2、组播分为两部分:
组播数据流:目的
组播控制流:(IGMP)分三种报文:report(join),leave,query
3、组播编程
int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
client:1、IP_MULTICAST_LOOP
2、IP_ADD_MEMBERSHIP
3、IP_DROP_MEMBERSHIP
netinet/in.h
/* Internet address. */
typedef uint32_t in_addr_t;
struct in_addr
{
in_addr_t s_addr;
};
#ifdef __USE_MISC
/* IPv4 multicast request. */
struct ip_mreq
{
/* IP multicast address of group. */
struct in_addr imr_multiaddr;
/* Local IP address of interface. */
struct in_addr imr_interface;
};
内容:组播客户端
要求:接收组播发布的消息,接收5次自动退出;
************************************************************************/
#include<stdio.h>
#include<string.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<errno.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#define MULTICAST_IP "224.255.255.255"
#define PORT 6667
int main(int argc,char *argv[])
{
int sockfd;
int i;
int addrlen,recvbytes,localen;
int opterr1,opterr2,opterr3,binderr;
int loopopt = 1;
int opt = 1;
char recvbuf[128];
struct sockaddr_in local ;
struct ip_mreq mcast_addr;
addrlen = sizeof(struct ip_mreq);
localen = sizeof(local);
sockfd =socket(AF_INET,SOCK_DGRAM,0);//建立socket
if(sockfd ==-1)
{
printf("creat socket error,errno:%d\n",errno);
return -1;
}
//套接字设为可重用
opterr1 = setsockopt(sockfd ,SOL_SOCKET ,SO_REUSEADDR, &opt,sizeof(opt));
if(opterr1< 0 )
{
perror("setsockopt1 error:\n");
}
//禁止组播数据回送
opterr2 = setsockopt(sockfd ,IPPROTO_IP ,IP_MULTICAST_LOOP,
&loopopt,sizeof(loopopt));
if(opterr2< 0 )
{
perror("setsockopt2 error:\n");
}
bzero(&local ,sizeof(local));
local.sin_family = AF_INET;
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_port = htons(PORT);
bzero(&mcast_addr,addrlen);
mcast_addr.imr_multiaddr.s_addr = inet_addr(MULTICAST_IP);
mcast_addr.imr_interface.s_addr = htonl(INADDR_ANY);
//将套接字与本地地址绑定
binderr = bind(sockfd,(struct sockaddr *)&local ,localen);
if(binderr < 0)
{
perror("Bind err:\n");
close(sockfd);
}
//加入组播组
opterr3 = setsockopt(sockfd ,IPPROTO_IP ,IP_ADD_MEMBERSHIP,
&mcast_addr, addrlen);
if(opterr3 < 0 )
{
perror("setsockopt3 error:\n");
}
//5次循环读取组播客户端发来的数据
for(i =0 ;i < 5 ;i++)
{
bzero(recvbuf, 128 );
recvbytes = recvfrom(sockfd,recvbuf,sizeof(recvbuf),0,(struct sockaddr*)(&local),&localen);
if(recvbytes< 0)
{
perror("recv msg error.\n");
}
printf("%d time recv msg:%s\n",i,recvbuf);
sleep(1);
}
//读取完毕,退出组播组,结束
setsockopt(sockfd ,IPPROTO_IP ,IP_DROP_MEMBERSHIP,
&mcast_addr, addrlen);
close(sockfd);
return 0;
}
内容:编写以组播服务器
要求:定期发送一组数据给加入组播组的所有客户端
************************************************************************/
#include<stdio.h>
#include<string.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<errno.h>
#include<string.h>
#include<unistd.h>
#define PORT 6667
#define MULTICAST_IP "224.255.255.255"
int main(int argc,char *argv[])
{
int sockfd;
int mcastlen,sendbytes;
int opterr;
int opt = 1;
char sendbuf[128] = "Hello,I am multicast server!welcom to join me!";
struct sockaddr_in mcast_addr;
//建立socket
mcastlen = sizeof(mcast_addr);
sockfd =socket(AF_INET,SOCK_DGRAM,0);
if(sockfd ==-1)
{
printf("creat socket error,errno:%d\n",errno);
return -1;
}
opterr = setsockopt(sockfd ,SOL_SOCKET ,SO_REUSEADDR, &opt,sizeof(opt));
if(opterr< 0 )
{
perror("setsockopt error:\n");
}
bzero(&mcast_addr,mcastlen);
mcast_addr.sin_family = AF_INET;
mcast_addr.sin_port = htons(PORT);
mcast_addr.sin_addr.s_addr = inet_addr(MULTICAST_IP);
while(1)
{
sendbytes = sendto(sockfd,sendbuf,strlen(sendbuf),0,(struct sockaddr*)(&mcast_addr),mcastlen);
if(sendbytes<0)
{
perror("send msg error.\n");
}
printf("send msg success!\n");
sleep(1);
}
return 0;
}
参考资料:
1、 linux网络编程之-----多播(组播)编程