广播:
主机之间“一对所有
”的通讯模式,网络对其中每一台主机发出的信号都进行无条件复制并转发
,所有主机都可以接收到所有信息(不管你是否需要),由于其不用路径选择,所以其网络成本可以很低廉。有线电视网就是典型的广播型网络,我们的电视机实际上是接受到所有频道的信号,但只将一个频道的信号还原成画面。在数据网络中也允许广播的存在,但其被限制在二层交换机的局域网范围内,禁止广播数据穿过路由器,防止广播数据影响大面积的主机
。
广播的优点:
- 网络设备简单,维护简单,布网成本低廉
- 由于服务器不用向每个客户机单独发送数据,所以
服务器流量负载极低
。
广播的缺点:
- 无法针对每个客户的要求和时间及时提供个性化服务。
- 网络允许服务器提供数据的带宽有限,客户端的最大带宽=服务总带宽。例如有线电视的客户端的线路支持100个频道(如果采用数字压缩技术,理论上可以提供500个频道),即使服务商有更大的财力配置更多的发送设备、改成光纤主干,也无法超过此极限。也就是说无法向众多客户提供更多样化、更加个性化的服务。
- 广播
禁止在Internet宽带网上传输
。
socket实现广播
TCP点对点的面向连接的协议不支持广播报文
,要实现广播报文,需要使用UDP协议。
socket()函数中AF协议族支持配置传输类型为UDP。
int socket(int domain, int type, int protocol);
type:
连接类型 | 作用 |
---|---|
SOCK_STREAM | 点对点的面向连接的TCP连接,字符流 |
SOCK_DGRAM | UDP数据报格式,无需连接,不保证数据到达 |
SOCK_RAW | 原始套接字。该套接字允许对较低层协议(如IP或ICMP)进行直接访问,常用于网络协议分析,检验新的网络协议实现,也可用于测试新配置或安装的网络设备 |
介绍一个函数
int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
sockfd:标识一个套接口的描述字。
level:选项定义的层次;支持SOL_SOCKET
、IPPROTO_TCP
、IPPROTO_IP
和IPPROTO_IPV6
。
optname:需设置的选项(比如这里需要设置广播SO_BROADCAST
)。
optval:指针,指向存放选项待设置的新值的缓冲区。
optlen:optval缓冲区长度。
传输未建立连接的UDP数据包, 需要使用sendto()函数。
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
该函数不阻塞,适用于UDP传输发出不管的特点。
程序
广播发送方:
- 创建socket,指定使用UDP协议;
- 指定端口,指定IP为广播地址;
- 设置socket为广播模式;
- 发送数据,发出不管是否接收成功,不阻塞。
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<errno.h>
#include<error.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
#include<unistd.h>
int main()
{
int fd;
struct sockaddr_in addr;
fd = socket(AF_INET,SOCK_DGRAM,0);
if(fd < 0)
{
printf("socket error:%s\n",strerror(errno));
return -1;
}
addr.sin_family = AF_INET;
addr.sin_port = htons(12345);
addr.sin_addr.s_addr = inet_addr("192.168.10.255");
int broad_flag = 1;
setsockopt(fd,SOL_SOCKET,SO_BROADCAST, &broad_flag,sizeof(int));
char *str = "hello world!";
while(1)
{
int ret = sendto(fd,str, strlen(str)+1,0,(struct sockaddr *)&addr,sizeof(struct sockaddr_in));
if(ret < 0)
{
printf("sendto error:%s\n",strerror(errno));
break;
}
printf("sendto ok!\n");
sleep(1);
}
close(fd);
return 0;
}
接收程序:
- 不建立连接,直接创建socket,指定UDP协议;
- 绑定端口;
- 开始接收消息。
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<errno.h>
#include<error.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
#include<unistd.h>
int main()
{
struct sockaddr_in addr,sendaddr;
char buf[1024]={0};
int fd = socket(AF_INET,SOCK_DGRAM,0);
if(fd < 0)
{
printf("socket error:%s\n",strerror(errno));
return -1;
}
addr.sin_family = AF_INET;
addr.sin_port = htons(12345);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(fd,(struct sockaddr *)&addr,sizeof(struct sockaddr_in));
if( ret < 0 )
{
printf("bind error:%s\n",strerror(errno));
return -1;
}
int len = sizeof(struct sockaddr_in);
while(1)
{
ret = recvfrom(fd, buf,sizeof(buf), 0, (struct sockaddr *)&sendaddr,&len);
if(ret < 0)
{
printf("recvfrom error:%s\n",strerror(errno));
break;
}
printf("recv from %s : %s\n",inet_ntoa(sendaddr.sin_addr),buf);
}
close(fd);
return 0;
}
运行效果:
- 不运行接收方程序,发送方依然可以发送消息(UDP传输不需要建立连接)
- 运行接收程序,在网段下的任何主机都能收到消息(广播)