嵌入式学习——3——多点通信

1、套接字选项(socket options)

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);

功能:获取或设置套接字在不同层级上的相关属性

参数:

sockfd:  要获取或设置的套接字文件描述符

level:     表示要获取或设置的层

                        应用层        SOL_SOCKET

                        传输层        IPPROTO_TCP  IPPROTO_UDP

                        网络层        IPPROTO_IP

optname:当前层的数下名称见下表

optval:     要获取或设置的属性值的起始地址

optlen:     optval的大小

返回值:成功 0   失败 -1  并重置错误码

快速重用地址

int reuse = 1;
if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))==-1) {
      perror("setsockopt error");
      return -1;
}

2、单播

1、主机之间存在的是一对一的通信方式,交换机以及路由器对数据只进行转发,不进行复制

2、每次只有两个实体之间进行相互通信,发送端和接收端都是唯一确定的

3、广播和组播的区别

组播是一种多对多的通信方式,其中消息被发送到一个特定的组播地址,只有加入该组播地址的主机才能接收到这个消息。组播允许发送方只向特定的一组接收方发送消息,可以在节省带宽的同时实现多对多通信,广泛应用于IP电话、视频会议、多媒体流等场景。


广播是一种发送消息给所有主机的通信方式。在广播中,消息被发送到一个广播地址,该地址会被所有网络中的主机接收。广播是一种无条件的发送方式,因此它常常被用于网络中一些需要向所有主机广播消息的场景,例如DHCP自动分配IP地址和ARP协议中解析MAC地址等。
总结:组播和广播的主要区别在于它们【发送消息的方式】和目【标接收者的范围不同】。广播是一种无条件的发送方式,消息被发送到所有主机;而组播则是有条件的发送方式,消息只会被发送到加入该组播地址的特定主机。

4、广播

1、广播是允许通信实体之间完成一对多的通信方式,网络对其中每一台发送数据的主机信息都进行无条件的复制后并转发给其他所有主机

2、所有的主机都会收到广播消息(不管是否愿意接收)

3、广播只能由UDP通信方式来实现

4、广播消息,只能在当前网络中进行传播,不允许传过路由器

5、广播地址:网络号 + 255

6、广播分为发送端和接收端实现

        3.1 广播的发送端------->类似于UDP的客户端

socket          创建用于通信的套接字文件描述符

setsockopt (SOL_SOCKET   SOBROADCAST )           设置该套接字允许发送广播消息

bind         绑定IP地址和端口号(可选)

sendto          向广播地址发送数据

        广播地址IP:网络号 + 255

        端口号:与接收端保持一致

close          关闭套接字

int main(){
    //1、创建用于通信的套接字文件描述符:socket
    int sfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sfd == -1)
    {
        perror("socket error");
        return -1;
    }

    //2、设置该套接字允许发送广播消息:setsockopt     ---> SOL_SOCKET 
    //---> SO_BROADCAST
    int broadcast = 1;
    if(setsockopt(sfd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)) ==-1)
    {
        perror("setsockopt error");
        return -1;
    }

    //3、绑定IP地址和端口号(可选)
    //4、向广播地址发送数据:sendto

    // 广播地址IP:网络号 + 255
    // 端口号:与接收端保持一致
    struct sockaddr_in rin;
    rin.sin_family = AF_INET;
    rin.sin_port = htons(6666);     //跟接收端保持一致
    rin.sin_addr.s_addr = inet_addr("xxx.xxx.xxx.255");


    //发送数据
    char wbuf[128] = "";
    while(1) {
       //从终端获取数据
       fgets(wbuf, sizeof(wbuf), stdin);
       wbuf[strlen(wbuf)-1] = 0;

       //发送给广播消息
       sendto(sfd, wbuf, strlen(wbuf), 0, (struct sockaddr*)&rin, sizeof(rin));
       printf("发送成功\n");

       //判断发送的消息
       if(strcmp(wbuf, "over") == 0)
       {
           break;
       }
    }

    //5、关闭套接字:close
    close(sfd);
    return 0;

}

        3.2 广播的接收端------->类似于UDP的服务器端

1、创建用于通信的套接字文件描述符

2、填充地址信息结构体:

        ip:广播地址

        port:与发送端保持一致

3、绑定端口号和IP地址(必须)

4、接受发送端发来的消息:recvfrom

5、关闭套接字:close

int main(){
    //1、创建用于通信的套接字文件描述符
    int rfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(rfd == -1) {
        perror("socket error");
        return -1;
    }

    //2、填充地址信息结构体:
    //ip:广播地址
    //port:与发送端保持一致
    struct sockaddr_in rin;
    rin.sin_family = AF_INET;
    rin.sin_port = htons(6666);     //端口号
    rin.sin_addr.s_addr = inet_addr("xxx.xxx.xxx.255"); //广播ip地址
    
    //3、绑定端口号和IP地址(必须)
    if(bind(rfd, (struct sockaddr*)&rin, sizeof(rin)) == -1) {
        perror("bind error");
        return -1;
    }
    //4、接受发送端发来的消息:recvfrom
    char rbuf[128] = "";
    while(1)
    {
        //清空容器
        bzero(rbuf, sizeof(rbuf));
        //读取数据
        recv(rfd, rbuf, sizeof(rbuf), 0);
        //展示
        printf("收到广播消息:%s\n", rbuf);

        //判断广播是否结束
        if(strcmp(rbuf, "over") == 0) {
            break;
        }
    }

    //5、关闭套接字:close
    close(rfd);
    return 0;
}

5、组播

1、由于广播通信过程中,会占用大量的网络带宽,影响正常通信,如果通信的主机较少的话,可以引入组播

2、组播也是实现主机之间一对多的通信方式

3、要求所有接受端主机加入多播组,只有加入多播组的主机才能收到消息

4、对于发送端而言,只需向该多播组中发送消息即可,无需其他设置

5、组播也是使用UDP实现的

6、组播地址:D类网络 【224.0.0.0 --- 239.255.255.255】

7、组播也分为发送端和接收端

        4.1 组播的发送端  ---> 类似于UDP的客户端流程

1、创建用于通信的套接字文件描述符:socket

2、绑定IP地址和端口号(可选)

3、向组播地址发送数据:sendto

        广播地址IP:【224.0.0.0 --- 239.255.255.255】

        端口号:与接收端保持一致

4、关闭套接字:close

int main()
{
    //1、创建用于通信的套接字文件描述符:socket
    int sfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sfd == -1)
    {
        perror("socket error");
        return -1;
    }

    //2、绑定IP地址和端口号(可选)
    //3、向组播地址发送数据:sendto
    //广播地址IP:【224.0.0.0 --- 239.255.255.255】
    //端口号:与接收端保持一致
    struct sockaddr_in rin;
    rin.sin_family = AF_INET;
    rin.sin_port = htons(5555);
    rin.sin_addr.s_addr = inet_addr("224.1.2.3");

    //数据的发送
   //发送数据
   char wbuf[128] = "";
   while(1)
   {
       //从终端获取数据
       fgets(wbuf, sizeof(wbuf), stdin);
       wbuf[strlen(wbuf)-1] = 0;

       //发送给广播消息
       sendto(sfd, wbuf, strlen(wbuf), 0, (struct sockaddr*)&rin, sizeof(rin));
       printf("发送成功\n");

       //判断发送的消息
       if(strcmp(wbuf, "over") == 0)
       {
           break;
       }
   }


    //5、关闭套接字:close
    close(sfd);

    return 0;
}

        4.2 组播的接收端流程 ---> 类似于UDP的服务器端流程

1、创建用于通信的套接字文件描述符:socket

2、将该套接字加入多播组:

        setsockopt ---> IPPROTO_IP --> IP_ADD_MEMBERSHIP

属性类型:

        #include <netinet/in.h>

        struct ip_mreqn {

                struct in_addr imr_multiaddr; /* 组播地址 */

                struct in_addr imr_address; /* 主机ip地址 */

                int imr_ifindex; /* 设备索引,可以通过 ip ad指令查看, 也可以填0,表示使用

                                        默认的索引*/ };

3、填充地址信息结构体:

        ip:组播地址

        port:与发送端保持一致

4、绑定端口号和IP地址(必须)

5、接受发送端发来的消息:recvfrom

6、关闭套接字:close

int main() {
    //1、创建用于通信的套接字文件描述符:socket
    int rfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(rfd == -1) {
        perror("socket error");
        return -1;
    }

    //2、将该套接字加入多播组:setsockopt   --->  IPPROTO_IP    --> IP_ADD_MEMBERSHIP 
    struct ip_mreqn  imr;
    imr.imr_multiaddr.s_addr = inet_addr("224.1.2.3");
    imr.imr_address.s_addr = inet_addr("xxx.xxx.xxx.xxx");//本机主机ip地址
    imr.imr_ifindex = 2;

    //设置套接字选项,加入多播组
    if(setsockopt(rfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr))==-1) {
        perror("setsockopt error");
        return -1;
    }

    //3、填充地址信息结构体:
    //ip:组播地址
    //port:与发送端保持一致
    struct sockaddr_in rin;
    rin.sin_family = AF_INET;
    rin.sin_addr.s_addr = inet_addr("224.1.2.3");
    rin.sin_port = htons(5555);

    //4、绑定端口号和IP地址(必须)
    if(bind(rfd, (struct sockaddr*)&rin, sizeof(rin)) == -1) {
        perror("bind error");
        return -1;
    }

    //5、接受发送端发来的消息:recvfrom
    char rbuf[128] = "";
    while(1) {
        //清空容器
        bzero(rbuf, sizeof(rbuf));

        //读取数据
        recv(rfd, rbuf, sizeof(rbuf), 0);

        //展示
        printf("收到广播消息:%s\n", rbuf);
        //判断广播是否结束

        if(strcmp(rbuf, "over") == 0) {
            break;
        }
    }

    //6、关闭套接字:close
    close(rfd);
    return 0;
}

  • 17
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值