学习记录——day31 多点通信 广播 组播

一、套接字属性

1、套接字属性获取及设置

       #include <sys/types.h>          /* See NOTES */
       #include <sys/socket.h>

       int getsockopt(int sockfd, int level, int optname,
 void *optval, socklen_t *optlen);
       int setsockopt(int sockfd, int level, int optname,
 const void *optval, socklen_t optlen);
       功能:设置套接字在不同层上的属性
       参数1:套接字文件描述符
       参数2:要设置的层
               应用层:SOL_SOCKET
               传输层:tcp传输:IPPROTO_TCP
                       udp传输:IPPROTO_UDP
               网络层: IPPROTO_IP           
        参数3:要设置当前层的属性名称 ,常用每层属性见下表
        参数4:要设置或者获取属性的值    ,一般为int类型
        参数5:参数4的大小
        返回值:成功     返回0,失败返回-1并置位错误码                

 2、案例:设置广播属性

#include<myhead.h>

int main(int argc, const char *argv[])
{
    //1、创建一个套接字
    int sfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sfd == -1)
    {
        perror("socket error");
        return -1;
    }


    //2、获取套接字地址重用的值
    int get_val = 1;
    socklen_t size = sizeof(get_val);       //获取属性值的大小
    if(getsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &get_val, &size) == -1)
    {
        perror("getsockopt error");
        return -1;
    }
    printf("get_val = %d\n", get_val);              //如果结果为0,表示套接字默认不允许端口号快速重用

    //3、设置允许端口号快速重用
    int set_val = 1;
    if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &set_val, sizeof(set_val)) ==-1)
    {
        perror("setsockopt error");
        return -1;
    }
    printf("端口号快速重用成功\n");

    //4、验证是否设置成功了
    get_val = 0;
    if(getsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &get_val, &size) == -1)
    {
        perror("getsockopt error");
        return -1;
    }
    printf("get_val = %d\n", get_val);      //如果结果为1,表示套接字端口号快速重用设置成功





    return 0;
}

二、网络通信方式 单播 广播 组播

1、单播:发送端和接收端完成一对一的通信方式。目前的通信模型都是单播

2、广播:发送端和接收端完成一对多的通信方式,网络将发送端的数据,全部复制一遍发送给每个接收端一份

3、组播:发送端和接收端完成一对多的通信方式,但是仅仅只限于加入多播组的成员

三、广播

1、广播相关概念

1)广播是实现网络通信中一对多的通信方式,发送端用于发送数据,每个接收端都可以收到消息

2)对于套接字而言,一般是不允许发送广播消息的,需要对发送端套接字进行设置允许广播

        setsockopt ---> SOL_SOCKET ----> SO_BROADCAST ----> int

3)广播的发送端需要绑定广播地址

        广播地址:网络号 + 255

        当前网络中,主机号为255的那个ip地址

4)广播消息不允许穿过路由器,广播地址只对当前局域网中的所有主机进行消息的转发

5)广播分为发送端和接收端,发送端用于发送数据,接收端用于接收数据

6)广播只能使用UDP实现,对于接入广播的接收端而言,广播发送的信息是不能选择性接收的

2、广播发送端代码实现

1、socket();          //创建用于通信的套接字文件描述符
2、bind();             //可选,可以绑定也可以不绑定
3、setsockopt();           //设置当前套接字允许广播
4、sendto();               //向广播地址发送消息
5、close();                //关闭套接字
#include <myhead.h>
int main(int argc, char const *argv[])
{
    // 创建通信用的套接字
    int sfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sfd == -1)
    {
        perror("socket errro");
        return -1;
    }
    printf("sfd = %d\n", sfd);

    /*//绑定(可选)
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_prot = htons(5555);
    sin.sin_addr.s_addr = inet_addr("192.168.232.255")

    bind(sfd,(struct sockaddr*)&rin,sizeof(rin) == -1)
    {
        perror("bind error");
        return -1;
    }
    */

    // 设置广播属性
    int broad = 1;
    if (setsockopt(sfd, SOL_SOCKET, SO_BROADCAST, &broad, sizeof(broad)) == -1)
    {
        perror("setsockopt error");
        return -1;
    }

    // 封装广播的地址信息
    struct sockaddr_in bin;
    bin.sin_family = AF_INET;
    bin.sin_port = htons(5555);
    bin.sin_addr.s_addr = inet_addr("192.168.232.255");
    // 终端指令ifconfig  找到 broadcast    广播ip地址

    //  发送信息
    char sbuf[128] = "";
    while (1)
    {
        printf("输入:");
        fgets(sbuf, sizeof(sbuf), stdin);
        sbuf[strlen(sbuf) - 1] = 0;
        sendto(sfd, sbuf, sizeof(sbuf), 0, (struct sockaddr *)&bin, sizeof(bin));
        bzero(sbuf, sizeof(sbuf));
    }

    close(sfd);
    return 0;
}

3、广播接收端代码实现

1、socket();          //创建用于通信的套接字文件描述符
2、bind();             //必须进行,但是,绑定的是广播地址和端口号
3、sendto();               //向广播地址发送消息
4、close();                //关闭套接字
#include <myhead.h>
int main(int argc, char const *argv[])
{
    //创建通信用的套接字
    int rfd = socket(AF_INET,SOCK_DGRAM,0);
    if (rfd == -1)
    {
        perror("socket errro");
        return -1;
    }
    printf("rfd = %d\n",rfd);

    //绑定
    struct sockaddr_in rin;
    rin.sin_family = AF_INET;
    rin.sin_port = htons(5555);
    rin.sin_addr.s_addr = inet_addr("192.168.232.255");
    // 终端指令ifconfig  找到 broadcast    广播ip地址

    if(bind(rfd,(struct sockaddr*)&rin,sizeof(rin)) == -1)
    {
        perror("bind error");
        return -1;
    }

    //接收信息
    char rbuf[128] = "";
    while (1)
    {
        recv(rfd,rbuf,sizeof(rbuf),0);
        printf("收到信息:%s\n",rbuf);
        bzero(rbuf,sizeof(rbuf));
    }
    
    close(rfd);
    return 0;
}

四、组播

1、组播相关概念

1)组播也是实现一对多的通信方式,对于广播而言,网络需要对每个消息进行复制转发,会占用大量的带宽,导致网络拥塞

2)组播可以实现小范围的数据传播:将需要接收数据的接收端加入多播组,发送端向多播组中发送消息,每个组内成员都能接收到消息

3)需要对接收端进行设置,将接收端加入多播组

需要使用setsockopt函数实现
需要对网络层设置:IPPROTO_IP
需要对加入多播组属性设置:IP_ADD_MEMBERSHIP
属性值的类型
struct ip_mreqn

        {
               struct in_addr imr_multiaddr; /* 组播地址:D类网络(224.0.0.0 ---                       239.255.255.255) */
               struct in_addr imr_address;   /* 当前主机IP地址 */
               int            imr_ifindex;   /* 网卡编号: 通过指令 ip ad查看 */
         };

2、组播发送端流程

1、socket();          //创建用于通信的套接字文件描述符
2、bind();             //可选,可以绑定也可以不绑定
3、sendto();               //向多播组地址发送消息
4、close();                //关闭套接字
#include <myhead.h>
int main(int argc, char const *argv[])
{
    int msfd = socket(AF_INET,SOCK_DGRAM,0);
    if (msfd == -1)
    {
        perror("socket error");
        return -1;
    }

    struct sockaddr_in min;
    min.sin_family = AF_INET;
    min.sin_port = htons(9999); //与发送端保持一致
    min.sin_addr.s_addr = inet_addr("224.6.6.6");

    char sbuf[128] = "";
    while (1)
    {
        printf("输入:");
        fgets(sbuf,sizeof(sbuf),stdin);
        sbuf[strlen(sbuf)-1] = 0;
        sendto(msfd,sbuf,sizeof(sbuf),0,(struct sockaddr*)&min,sizeof(min));
        printf("发送结束\n");
    }
    
    close(msfd);
    return 0;
}

3、组播的接收端流程

1、socket();          //创建用于通信的套接字文件描述符
2、bind();             //必须进行,但是,绑定的组播地址和端口号
3、setsockopt();          //加入多播组
4、sendto();               //向广播地址发送消息
5、close();                //关闭套接字
#include <myhead.h>
int main(int argc, char const *argv[])
{
    int mrfd = socket(AF_INET,SOCK_DGRAM,0);
    if (mrfd == -1)
    {
        perror("socket error");
        return -1;
    }
    //定义地址信息结构体
    struct sockaddr_in mrin;
    mrin.sin_family = AF_INET;
    mrin.sin_port = htons(9999); //与发送端保持一致
    mrin.sin_addr.s_addr = inet_addr("224.6.6.6");//组播地址 224——239
    if (bind(mrfd,(struct sockaddr*)&mrin,sizeof(mrin)) == -1)
    {
        perror("bind error");
        return -1;
    }
    
    //多播组信息结构体
    struct ip_mreqn imr;
    imr.imr_multiaddr.s_addr = inet_addr("224.6.6.6");
    imr.imr_address.s_addr = inet_addr("192.168.232.255");
    imr.imr_ifindex =2;
    if (setsockopt(mrfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&imr,sizeof(imr)) == -1)
    {
        perror("setsockopt error");
        return -1;
    }
    printf("join membership success\n");

    char rbuf[128] = "";
    while (1)
    {
        recv(mrfd,rbuf,sizeof(rbuf),0);

        printf("接收到组播信息:%s\n",rbuf);
    }
    
    close(mrfd);
    return 0;
}

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值