socket--Linux下的广播

广播:

主机之间“一对所有”的通讯模式,网络对其中每一台主机发出的信号都进行无条件复制并转发,所有主机都可以接收到所有信息(不管你是否需要),由于其不用路径选择,所以其网络成本可以很低廉。有线电视网就是典型的广播型网络,我们的电视机实际上是接受到所有频道的信号,但只将一个频道的信号还原成画面。在数据网络中也允许广播的存在,但其被限制在二层交换机的局域网范围内,禁止广播数据穿过路由器,防止广播数据影响大面积的主机

广播的优点:

  • 网络设备简单,维护简单,布网成本低廉
  • 由于服务器不用向每个客户机单独发送数据,所以服务器流量负载极低

广播的缺点:

  • 无法针对每个客户的要求和时间及时提供个性化服务。
  • 网络允许服务器提供数据的带宽有限,客户端的最大带宽=服务总带宽。例如有线电视的客户端的线路支持100个频道(如果采用数字压缩技术,理论上可以提供500个频道),即使服务商有更大的财力配置更多的发送设备、改成光纤主干,也无法超过此极限。也就是说无法向众多客户提供更多样化、更加个性化的服务。
  • 广播禁止在Internet宽带网上传输

socket实现广播

TCP点对点的面向连接的协议不支持广播报文,要实现广播报文,需要使用UDP协议。

socket()函数中AF协议族支持配置传输类型为UDP。

int socket(int domain, int type, int protocol);

type:

连接类型作用
SOCK_STREAM点对点的面向连接的TCP连接,字符流
SOCK_DGRAMUDP数据报格式,无需连接,不保证数据到达
SOCK_RAW原始套接字。该套接字允许对较低层协议(如IP或ICMP)进行直接访问,常用于网络协议分析,检验新的网络协议实现,也可用于测试新配置或安装的网络设备

介绍一个函数

int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);

sockfd:标识一个套接口的描述字。
level:选项定义的层次;支持SOL_SOCKETIPPROTO_TCPIPPROTO_IPIPPROTO_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传输发出不管的特点。

程序

广播发送方:
  1. 创建socket,指定使用UDP协议;
  2. 指定端口,指定IP为广播地址;
  3. 设置socket为广播模式;
  4. 发送数据,发出不管是否接收成功,不阻塞。
#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;
}
接收程序:
  1. 不建立连接,直接创建socket,指定UDP协议;
  2. 绑定端口;
  3. 开始接收消息。
#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传输不需要建立连接)

  • 运行接收程序,在网段下的任何主机都能收到消息(广播)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值