多点通信
单播
- 单播发生在主机之间一对一的通信模式,交换机或者路由器只对数据进行转发,不做复制
- 每次只有两个实体之间进行相互通信,发送端和接收端都是唯一确定的
广播
- 主机之间的一对多的通信模式,网络对其中的每一台主机发出的信息都进行复制并转发
- 所有主机都可以收到广播消息(无论你是否愿意接收),所以,广播是基于UDP通信模式
- 广播地址:网络号 + 255
例如:主机地址为192.168.125.171 —> 192.168.125.255 - 广播消息是不能穿过路由器的,也就是说广播消息禁止在外网上进行传播,所以广播只能完成局域网内的多点通信
广播发送端模型
- socket 创建套接字
- setsockopt 设置网络属性,允许广播
- bind 非必须绑定(绑定的话每次发送端口都是固定的)
- 填广播地址信息结构体
ip:填广播地址(192.168.125.255)
port:与接收端保持一致 - sendto 发送消息
- close 关闭套接字
广播的接收端模型
- socket 创建套接字
- 填充地址信息结构体
ip:广播地址(192.168.125.255)
port:与发送端保持一致 - bind 绑定端口号与ip地址
- recvfrom 接收消息
- close 关闭套接字
作业
广播的实现
//发送端
#include <myhead.h>
//广播IP以及端口号
#define BOR_IP "192.168.124.255"
#define BOR_PORT 8888
//自身IP以及端口号
#define IP "192,168.124.112"
#define PORT 6666
int main(int argc, const char *argv[])
{
//创建套接字
int socketfd = socket(AF_INET, SOCK_DGRAM, 0);
if (socketfd == -1)
{
perror("socket");
return -1;
}
//允许广播
int k = 1;
if ( setsockopt(socketfd, SOL_SOCKET, SO_BROADCAST, &k, sizeof(k)) == -1 )
{
perror("setsocketopt");
return -1;
}
printf("成功开启广播\n");
//绑定自身套接字
struct sockaddr_in send = {
.sin_family = AF_INET,
.sin_port = htons(PORT),
.sin_addr.s_addr = inet_addr(IP)
};
if (bind(socketfd, (struct sockaddr *)&send, sizeof(send)) == -1)
{
perror("bind");
return -1;
}
//广播IP等信息
struct sockaddr_in boradcast = {
.sin_family = AF_INET,
.sin_port = htons(BOR_PORT),
.sin_addr.s_addr = inet_addr(BOR_IP)
};
char buff[1024] = "";
while (1)
{
//输入
fgets(buff, sizeof(buff), stdin);
buff[strlen(buff) - 1] = '\0';
//发送到广播地址
sendto(socketfd, buff, strlen(buff), 0, (struct sockaddr *)&boradcast, sizeof(boradcast));
if (strcmp(buff, "quit") == 0)
{
printf("发送端退出\n");
break;
}
bzero(buff, sizeof(buff));
}
return 0;
}
//接收端
#include <myhead.h>
//广播IP以及端口号
#define IP "192.168.124.255"
#define PORT 8888
int main(int argc, const char *argv[])
{
//创建套接字
int socketfd = socket(AF_INET, SOCK_DGRAM, 0);
if (socketfd == -1)
{
perror("socket");
return -1;
}
//广播IP等信息
struct sockaddr_in recv = {
.sin_family = AF_INET,
.sin_port = htons(PORT),
.sin_addr.s_addr = inet_addr(IP)
};
//绑定广播地址
if (bind(socketfd, (struct sockaddr *)&recv, sizeof(recv)) == -1)
{
perror("bind");
return -1;
}
char buff[1024] = "";
while (1)
{
//接收信息
recvfrom(socketfd, buff, sizeof(buff), 0,NULL,NULL);
printf("收到信息:%s\n", buff);
bzero(buff,sizeof(buff));
}
return 0;
}
组播
- 组播也是实现主机之间一对多的通信模型,跟广播不同的是,组播发送的消息,只有加入多播组的成员才能收到,没有加入的就无法收到,不会占用柜台的网络带宽
- 组播也是使用UDP实现
- 组播地址:就是D类网络,224.0.0.0 – 239.255.255.255
组播的发送端模型
- socket 创建套接字
- bind 非必须绑定
- 填充接收端地址信息结构体
ip:组播地址,与接收端保持一致(224.0.0.0 – 239.255.255.255)
port:与接收端保持一致 - sendto 发送组播消息
- close 关闭套接字
特点:
- 发送端发送给组播组IP和端口号
- 发送端不需要绑定自己的IP和端口号,只需要发送到组播地址即可
组播接收端模型
- socket 创建套接字
- setsockopt 设置网络属性(加入多播组)
设置层级:IPPROTO_IP
设置属性:IP_ADD_MEMBERSHIP
struct ip_mreqn {
struct in_addr imr_multiaddr; /* 组播IP
struct in_addr imr_address; /* 本机IP*/
int imr_ifindex; /* 网卡索引 */
};
- 填充地址信息结构体然后bind
ip:组播IP,与发送端保持一致
port :与发送端保持一致 - 定义发送方结构体,接收发送方信息
- recvfrom 接收消息
- close 关闭套接字
特点:
- 设置允许加入组播组(发送端的IP),设置加入组播组时需要(组播组IP,自己的IP,自己网卡ens33的索引号一般都是2)
- 查找自己网卡的索引号:ip addr show或者ip ad
- 绑定时绑定的是组播组IP和发送端IP保持一致
- 接收端也可以选择不接收发送方信息,recvfron最后两个参数填NULL即可