目录
1.组播基本知识
2.组播编程实现
2.1 服务器端
2.2 客户端
1.组播基本知识
由于设计到多播通信方法,故查阅资料学习一下,三种通信方法:
类型 | 特点 | 优缺点 | 使用方法 |
单播 | 用于两个主机之间的端对端通信 | 单播解决了点对点通信的需求; | TCP/UDP |
广播 | 用于一个主机对整个局域网上所有主机上的数据通信 | 存在缺点: 1)只能在同一网段内实现广播; 2)不能指定目的主机,所有网段内的主机都将收到广播报文,存在带宽浪费。 | UDP |
多播 | 将局域网中同一业务类型主机进行了逻辑上的分组,进行数据收发的时候其数据仅仅在同一分组中进行 | 1.组播也是点对多点的通信,完全克服了广播的两个缺点,广泛应用实时性较高的信息服务。 2.可以局域网也可以是互联网 | UDP |
D类地址用于多播。即224.0.0.0至239.255.255.255之间的IP地址,并被划分为局部连接多播地址、预留多播地址和管理权限多播地址3类:
类型 | 地址区间 | 特点 |
局部多播地址 | 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,可限制多播范围。 |
注意:TCP是基于面向连接的通信方式,只能点对点,故只能是单播
而UDP是传输之前不需要建议连接,可以是单播,多播和广播;
2.组播编程实现
多播程序设计使用setsockopt()函数和getsockopt()函数来实现,组播的选项是IP层的。参数如下:
宏定义 | 含义 | 示例 |
IP_MULTICAST_TTL | 设置多播组数据的TTL值 | 选项IP_MULTICAST_TTL允许设置超时TTL, 范围为0~255之间的任何值,例如: unsigned char ttl=255; |
IP_ADD_MEMBERSHIP | 在指定接口上加入组播组 | 加入或者退出一个多播组,通过选项IP_ADD_MEMBERSHIP和IP_DROP_MEMBER- SHIP,对一个结构struct ip_mreq类型的变量进行控制,struct ip_mreq原型如下: struct ip_mreq }; struct ip_mreq mreq; setsockopt(s,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq)); |
IP_DROP_MEMBERSHIP | 退出组播组 | |
IP_MULTICAST_IF | 获取默认接口或设置接口 | 选项IP_MULTICAST_IF用于设置组播的默认默认网络接口,会从给定的网络接口发送,另一个网络接口会忽略此数据。例如: struct in_addr addr; setsockopt(s,IPPROTO_IP,IP_MULTICAST_IF,&addr,sizeof(addr)); |
IP_MULTICAST_LOOP | 禁止组播数据回送 | 默认情况下,当本机发送组播数据到某个网络接口时,在IP层,数据会回送到本地的回环接口,选项IP_MULTICAST_LOOP用于控制数据是否回送到本地的回环接口。例如: unsigned char loop; |
2.1 服务器端
linux多播服务端编程思路:
1>建立一个socket;
2>设置多播的IP地址
3>发送和接收数据
服务器不需要加入多播组,可以直接向某个多播组发送数据。
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#define MCAST_PORT 8888;
#define MCAST_ADDR "224.0.0.100"/
#define MCAST_DATA "BROADCAST TEST DATA"
#define MCAST_INTERVAL 5
int main(int argc, char*argv)
{
struct sockaddr_in mcast_addr;
int soketfd = socket(AF_INET, SOCK_DGRAM, 0); /*建立套接字*/
if (s == -1)
{
perror("socket()");
return -1;
}
memset(&mcast_addr, 0, sizeof(mcast_addr));
mcast_addr.sin_family = AF_INET;
mcast_addr.sin_addr.s_addr = inet_addr(MCAST_ADDR);
mcast_addr.sin_port = htons(MCAST_PORT);
/*向多播地址发送数据*/
while(1) {
int n = sendto(soketfd, MCAST_DATA, sizeof(MCAST_DATA), 0, (struct sockaddr*)&mcast_addr,sizeof(mcast_addr)) ;
if( n < 0)
{
perror("sendto()");
return -2;
}
sleep(MCAST_INTERVAL);
}
return 0;
}
2.2 客户端
linux多播客户端编程思路:
1>建立一个socket;
2>设置多播的参数,例如超时时间TTL,本地回环许可LOOP等
3>加入多播组
4>发送和接收数据
5>从多播组离开
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#define MCAST_PORT 8888;
#define MCAST_ADDR "224.0.0.100"
#define MCAST_INTERVAL 5
#define BUFF_SIZE 256
int main(int argc, char*argv[])
{
struct sockaddr_in local_addr; /*本地地址*/
int clientfd = socket(AF_INET, SOCK_DGRAM, 0); /*建立套接字*/
if (clientfd == -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(MCAST_PORT);
int err = bind(clientfd,(struct sockaddr*)&local_addr, sizeof(local_addr)) ;
if(err < 0)
{
perror("bind()");
return -2;
}
int loop = 1;
err = setsockopt(clientfd,IPPROTO_IP, IP_MULTICAST_LOOP,&loop, sizeof(loop));
if(err < 0)
{
perror("setsockopt():IP_MULTICAST_LOOP");
return -3;
}
struct ip_mreq mreq; /*加入多播组*/
mreq.imr_multiaddr.s_addr = inet_addr(MCAST_ADDR); /*多播地址*/
mreq.imr_interface.s_addr = htonl(INADDR_ANY); /*网络接口为默认*/
err = setsockopt(s, 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[BUFF_SIZE];
int n = 0;
for(times = 0;times<5;times++)
{
addr_len = sizeof(local_addr);
memset(buff, 0, BUFF_SIZE);
n = recvfrom(clientfd, buff, BUFF_SIZE, 0,(struct sockaddr*)&local_addr,
&addr_len);
if( n== -1)
{
perror("recvfrom()");
}
printf("Recv %dst message from server:%s\n", times, buff);
sleep(MCAST_INTERVAL);
}
err = setsockopt(clientfd, IPPROTO_IP, IP_DROP_MEMBERSHIP,&mreq, sizeof
(mreq));
close(clientfd);
return 0;
}