组播 又称为 多播,只有加入某个多播组的主机才能收到数据。
组播的地址
D类地址
不分网络地址和主机地址,第1字节的前4位固定为1110(224.0.0.1 – 239.255.255.255)
224D <==>1110 0000B
D类ip地址,每一个都可以代表一个多播组。
发送者:
1.创建套接字 socket( )
2.填充组播信息结构体 sockaddr_in
3.发送数据 sendto( )
-------
接收者:|
-------
1.创建套接字 scoket( )
2.填充组播信息结构体 sockaddr_in
3.将套接字与组播信息结构体绑定 bind( )
------------------------------------
4.设置为加入多播组 setsockopt( )
------------------------------------
5.接收数据 recvfrom( )
#include
#include
int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
参数:
sockfd:套接字
level:选项的级别
IPPROTO_IP IP级别
optname:选项的名称
IP_ADD_MEMBERSHIP 在指定接口上加入组播组
optval:结构体
struct ip_mreqn {
struct in_addr imr_multiaddr; /* 多播组的地址 */
struct in_addr imr_address; /* 本地的IP地址 */
int imr_ifindex; /* 接口索引 0 表示任意接口 */
};
optlen:optval的大小
setsockopt 其他用法
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ERRLOG(errmsg) \
do \
{ \
printf("%s--%s(%d):", __FILE__, __func__, __LINE__); \
perror(errmsg); \
exit(-1); \
} while (0)
//创建套接字-填充服务器网络信息结构体-绑定
int socket_bind(const char *argv[]);
int main(int argc, const char *argv[])
{
//检测命令行参数个数
if (3 != argc)
{
printf("Usage : %s \n" , argv[0]);
exit(-1);
}
//创建套接字-填充服务器网络信息结构体-绑定
int sockfd = socket_bind(argv);
//用来保存发送端信息的结构体
// UPD网络通信 如果需要给发送端回信,就必须保存发送端的网络信息结构体
struct sockaddr_in client_addr;
memset(&client_addr, 0, sizeof(client_addr));
socklen_t client_addr_len = sizeof(client_addr);
/*-------------------------------------------------------------------------------------------------*/
//设置加入多播组
struct ip_mreqn mreq;
mreq.imr_multiaddr.s_addr = inet_addr(argv[1]); //多播组ip地址
mreq.imr_address.s_addr = inet_addr("192.168.250.100"); //本地ip地址
mreq.imr_ifindex = 0; // 接口索引 0 表示任意接口
// /套接字 /IP级别 /在指定接口上加入组播组
if (-1 == setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(struct ip_mreqn)))
ERRLOG("setsockopt error");
/*-------------------------------------------------------------------------------------------------*/
char buff[128] = {0};
while (1)
{
//阻塞接收发送端发来的数据
if (-1 == recvfrom(sockfd, buff,sizeof(buff), 0, (struct sockaddr *)&client_addr, &client_addr_len))
ERRLOG("recvfrom error");
printf("客户端 (%s:%d) 发来数据:[%s]\n",
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), buff);
}
//关闭监听套接字 一般不关闭
close(sockfd);
return 0;
}
//创建套接字-填充服务器网络信息结构体-绑定
int socket_bind(const char *argv[])
{
// 1.创建套接字 //IPV4 //UDP
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (-1 == sockfd)
ERRLOG("socket error");
// 2.填充广播信息结构体
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
//端口号 填 8888 9999 6789 ...都可以
server_addr.sin_port = htons(atoi(argv[2]));
// ip地址 组播的IP地址 224.0.0.1 – 239.255.255.255
server_addr.sin_addr.s_addr = inet_addr(argv[1]);
//结构体长度
socklen_t server_addr_len = sizeof(server_addr);
// 3.将套接字和组播信息结构体绑定
if (-1 == bind(sockfd, (struct sockaddr *)&server_addr, server_addr_len))
ERRLOG("bind error");
return sockfd;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ERRLOG(errmsg) \
do \
{ \
printf("%s--%s(%d):", __FILE__, __func__, __LINE__); \
perror(errmsg); \
exit(-1); \
} while (0)
int main(int argc, const char *argv[])
{
//检测命令行参数个数
if (3 != argc)
{
printf("Usage : %s \n" , argv[0]);
exit(-1);
}
// 1.创建套接字 //IPV4 //UDP
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (-1 == sockfd)
ERRLOG("socket error");
// 2.填充组播信息结构体
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr)); // 清空
server_addr.sin_family = AF_INET; // IPV4
//端口号 填 8888 9999 6789 ...都可以
// atoi字符串转换成整型数
// htons将无符号2字节整型 主机-->网络
server_addr.sin_port = htons(atoi(argv[2]));
// ip地址 是组播的ip地址 224.0.0.1 – 239.255.255.255
// inet_addr字符串转换成32位的网络字节序二进制值
server_addr.sin_addr.s_addr = inet_addr(argv[1]);
//结构体长度
socklen_t server_addr_len = sizeof(server_addr);
char buff[128] = {0};
while (1)
{
printf("请输入 : ");
scanf("%s", buff);
if (0 == strcmp(buff, "quit"))
break;
//将数据以组播的形式发送----发送到组播的ip地址
if (-1 == sendto(sockfd, buff,sizeof(buff), 0, (struct sockaddr *)&server_addr, server_addr_len))
ERRLOG("sendto error");
}
//关闭监听套接字 一般不关闭
close(sockfd);
return 0;
}
在 接收端 使用 setsockopt 设置加入多播组
应该插放在 bind 将套接字和网络信息结构体绑定 之后,recvfrom接收发送端数据之前
设置加入多播组
struct ip_mreqn mreq;
mreq.imr_multiaddr.s_addr = inet_addr(argv[1]); //多播组ip地址
mreq.imr_address.s_addr = inet_addr("192.168.250.100"); //本地ip地址
mreq.imr_ifindex = 0; // 接口索引 0 表示任意接口
/套接字 /IP级别 /在指定接口上加入组播组
if (-1 == setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(struct ip_mreqn)))
ERRLOG("setsockopt error");