1. 广播
1.1 知识点
INADDR_ANY代表本机所有地址 常用方法当你将套接字绑定到INADDR_ANY,它会监听所有可用的网络接口,这意味着它将接受来自所有本地IP地址的传入连接或数据包
1.1.1 广播的流程
广播发送端: ----> 添加广播属性
1、建立套接字
2、设置该套接字允许进行广播(将广播属性添加进去)
3、填充服务端的结构体广播网络地址
4、将数据发送到广播地址中(sendto)
5、关闭
接收端(服务器): ----> 绑定所有主机(INADDR_ANY)
1、建立套接字
2、设置该套接字允许进行广播(将广播属性添加进去)
3、填充服务端的结构体, 将套接字与广播信息结构体绑定(广播地址和端口号(端口号和广播端口一致))
4、创建结构体存放发送端IP和端口
5、接收数据 recvfrom( )
6、关闭
1.1.2 函数
接口声明:setsockopt() 函数:用于设置套接字选项,以启用广播功能。
参数:
sockfd:套接字文件描述符。
level:指定选项所属的协议层,通常是 SOL_SOCKET。
optname:指定要设置的选项,通常是 SO_BROADCAST,表示启用广播。
optval:指向一个整数变量的指针,通常设置为 1 表示启用广播。
optlen:optval 变量的大小
返回值:
setsockopt() 函数的返回值通常是整数类型的,表示函数调用的成功与否。在成功设置套接字选项时,setsockopt() 返回0,表示操作成功。如果出现错误,则返回-1,并且可以使用 errno 全局变量来确定导致错误的具体原因。
1.2 广播发送消息
发送端broadcast_s.c
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
//广播发送消息
//发送端
int main()
{
//1. 创建udp套接字
int sock_fd = socket(AF_INET,SOCK_DGRAM,0);
//2. 用于设置为允许发送广播权限(套接字默认关闭广播属性),以启用广播功能。
int optval = 1;
socklen_t optval_len = sizeof(optval);//计算长度
int ret = setsockopt(sock_fd,SOL_SOCKET,SO_BROADCAST,&optval,optval_len);//SOL_SOCKET协议,SO_BROADCAST开启广播
if(-1==ret){
perror("开启广播失败");
return -1;
}
//这些没必要写,写了也没事
// local_addr.sin_family = AF_INET;//网际协议
// local_addr.sin_port = htons(8888);//设置端口 //htons功能是转为主机字节序
// local_addr.sin_addr.s_addr = INADDR_ANY;//设置ip INADDR_ANY自动获取本机ip
// socklen_t local_addr_len = sizeof(local_addr);//计算本机网络地址大小
// //绑定
// bind(sock_fd,(struct sockaddr*)&local_addr,local_addr_len);
//3. 初始化广播地址
struct sockaddr_in broadcast_addr;
broadcast_addr.sin_family = AF_INET;//网际协议
broadcast_addr.sin_port = htons(10000);//设置端口 //htons功能是转为主机字节序
broadcast_addr.sin_addr.s_addr = inet_addr("192.168.124.255");//设置ip
socklen_t broadcast_addr_len = sizeof(broadcast_addr);//计算广播网络地址大小
char sbuf[128];
while(1){
memset(sbuf,0,sizeof(sbuf));
fgets(sbuf,sizeof(sbuf),stdin);
//4. 广播发送
sendto(sock_fd,sbuf,sizeof(sbuf),0,(struct sockaddr*)&broadcast_addr,broadcast_addr_len);
}
return 0;
}
接收端broadcast_r.c
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
//广播发送消息
//接收端
int main()
{
//1. 创建udp套接字
int sock_fd = socket(AF_INET,SOCK_DGRAM,0);
if(sock_fd ==-1)
{
perror("open sock failed");
return -1;
}
//2. 用于设置套接字选项,以启用广播功能。
int optval = 1;
socklen_t optval_len = sizeof(optval);//计算长度
int ret = setsockopt(sock_fd,SOL_SOCKET,SO_BROADCAST,&optval,optval_len);//SOL_SOCKET协议,SO_BROADCAST开启广播
if(-1==ret){
perror("开启广播失败");
return -1;
}
//3. 初始化广播地址和绑定套接字
struct sockaddr_in local_addr;
local_addr.sin_family = AF_INET;//网际协议
//接收端端口必须和广播端口一致
local_addr.sin_port = htons(10000);//设置端口 //htons功能是转为主机字节序
//INADDR_ANY代表本机所有地址 常用方法当你将套接字绑定到INADDR_ANY,它会监听所有可用的网络接口
//,这意味着它将接受来自所有本地IP地址的传入连接或数据包
local_addr.sin_addr.s_addr = INADDR_ANY;//设置ip
socklen_t local_addr_len = sizeof(local_addr);//计算本机网络地址大小
//绑定
bind(sock_fd,(struct sockaddr*)&local_addr,local_addr_len);
//4. 定义结构体接收网络地址信息
struct sockaddr_in broadcast_addr;
socklen_t broadcast_addr_len = sizeof(broadcast_addr);//计算本机网络地址大小
char rbuf[128];
while(1){
memset(rbuf,0,sizeof(rbuf));
//5. 接收消息
recvfrom(sock_fd,rbuf,sizeof(rbuf),0,(struct sockaddr*)&broadcast_addr,&broadcast_addr_len);
//将是一个用于将 IPv4 地址从二进制形式转换为点分十进制字符串形式的C库函数。
char *ip = inet_ntoa(broadcast_addr.sin_addr);//ip
unsigned short port = ntohs(broadcast_addr.sin_port);//端口号
printf("%s %u接收广播的消息为:%s\n",ip,port,rbuf);
}
return 0;
}
2. 组播
2.1 知识点
2.1.1 组播特点
1)需要给组播设置IP地址,该IP必须是D类地址
2)只有UDP才能设置组播
3) IP地址分类 IP地址 = 网络号 + 主机号
网络号:指的是不同的网络
主机号:指的是同一个网段下用来识别不同的主机。
那也就是说,主机号所占的位数越多,在该网段下的主机 数越多
A类地址 :保留给政府机构使用
A类IP地址就由1字节的网络地址和3字节主机地址组成,网络地址的最高位必须 是“0”
A类地址范围 1.0.0.1 - 126.255.255.254
B类地址 :分配给中等规模的公司
B类IP地址就由2字节的网络地址和2字节主机地址组成,网络地址的最高位必须 是“10”
B类地址范围 128.0.0.1 - 191.255.255.254
C类地址 :分配给任何需要的人
C类IP地址就由3字节的网络地址和1字节主机地址组成,网络地址的最高位必须 是“110” 13 C类地址范围 192.0.0.1 - 223.255.255.254
D类地址 :用于组播
D类地址范围 224.0.0.1 - 239.255.255.254
E类地址 :用于实验
E类地址范围 240.0.0.1 - 255.255.255.254
2.1.2 组播通信的过程
UDP组播发送端
1、建立套接字()
2、设置组播地址等属性
3、发送数据
4、关闭
UDP组播接收端
1、建立套接字
2、定义组播结构体,设置组播ip(初始化 组播结构体)
3、加入组播属性(也就是设置这个套接字 可以接收组播信息)
4、绑定IP地址和端口号
5、创建结构体存放IP和端口
6、接收数据
7、关闭
组播结构体
struct ip_mreq
{
struct in_addr imr_multiaddr; //组播地址
struct in_addr imr_interface; //本机地址
}
struct in_addr imr_multiaddr
{
s_addr;//组播地址
}
struct in_addr imr_interface
{
s_addr;//本机地址
}
2.2 组播通信
发送端zubo_s.c
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
//组播发送消息
//发送端
int main()
{
//1.创建udp套接字
int sock_fd = socket(AF_INET,SOCK_DGRAM,0);
if(sock_fd ==-1)
{
perror("open sock failed");
return -1;
}
//2.初始化组播地址
struct sockaddr_in send_addr;
send_addr.sin_family = AF_INET;//网际协议
//接收端端口必须和组播端口一致
send_addr.sin_port = htons(10002);//设置端口
send_addr.sin_addr.s_addr = inet_addr("224.0.0.1");//设置组播ip
socklen_t send_addr_len = sizeof(send_addr);//计算本机网络地址大小
char sbuf[128];
while(1){
memset(sbuf,0,sizeof(sbuf));
fgets(sbuf,sizeof(sbuf),stdin);
//3. 发送消息
sendto(sock_fd,sbuf,sizeof(sbuf),0,(struct sockaddr*)&send_addr,send_addr_len);
}
//4. 关闭
close(sock_fd);
return 0;
}
接收端zubo_r.c
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
//组播发送消息
//接收端
int main()
{
//1.创建udp套接字
int sock_fd = socket(AF_INET,SOCK_DGRAM,0);
if(sock_fd ==-1)
{
perror("open sock failed");
return -1;
}
//2.定义组播结构体,设置组播ip(初始化 组播结构体)
struct ip_mreq m;
m.imr_multiaddr.s_addr = inet_addr("224.0.0.1");//组播地址
m.imr_interface.s_addr = INADDR_ANY;//主机地址(需要添加到组的ip)
socklen_t m_len = sizeof(m);
//3.加入组播属性(也就是设置这个套接字 可以接收组播信息)
setsockopt(sock_fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&m,m_len);
//4.初始化本地地址和绑定套接字
struct sockaddr_in local_addr;
local_addr.sin_family = AF_INET;//网际协议
local_addr.sin_port = htons(10002);//设置端口 //htons功能是转为主机字节序
local_addr.sin_addr.s_addr = INADDR_ANY;//设置ip
socklen_t local_addr_len = sizeof(local_addr);//计算本机网络地址大小
//绑定
bind(sock_fd,(struct sockaddr*)&local_addr,local_addr_len);
//5. 定义结构体接收网络地址信息
struct sockaddr_in recv_addr;
socklen_t recv_addr_len = sizeof(recv_addr);//计算本机网络地址大小
char rbuf[128];
while(1){
memset(rbuf,0,sizeof(rbuf));
//6. 接收消息
recvfrom(sock_fd,rbuf,sizeof(rbuf),0,(struct sockaddr*)&recv_addr,&recv_addr_len);
//将是一个用于将 IPv4 地址从二进制形式转换为点分十进制字符串形式的C库函数。
char *ip = inet_ntoa(recv_addr.sin_addr);//ip
unsigned short port = ntohs(recv_addr.sin_port);//端口号
printf("接收%s %u的组播消息为:%s\n",ip,port,rbuf);
}
//7. 关闭
close(sock_fd);
return 0;
}