嵌入式学习记录5.18(多点通信)

一、套接字属性设置相关函数

cpp 复制代码
       #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 (man 7 socket)
               传输层(TCP):IPPROTO_TCP (man 7 tcp)
               传输层(UDP):IPPROTO_UDP (man 7 udp)
               网络层:IPPROTO_IP (man 7 ip)
        参数3:当前层要设置或获取的属性名称,每层常设置的名称如下表所示:
       参数4:要给参数3属性设置的值
       参数5:参数4的大小
       返回值:成功返回0,失败返回-1并置位错误码
cpp 复制代码
#include<myhead.h>

int main(int argc, const char *argv[])
{
    //创建套接字
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd == -1)
    {
        perror("socket errorr");
        return -1;
    }

    //想要知道当前套接字能否进行端口号和地址的快速重用
    int reuse = -1;
    int optlen = sizeof(reuse);
    if(getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, &optlen) ==-1)
    {
        perror("getsockopt error");
        return -1;
    }

    printf("reuse = %d\n", reuse);        // 0,表示套接字默认不允许端口号快重用

    //设置端口号快速重用
    int optval = 1;
    if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1)
    {
        perror("setsockopt error");
        return -1;
    }

    //再次获取套接字属性的值
    reuse = -1;
    if(getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, &optlen) ==-1)
    {
        perror("getsockopt error");
        return -1;
    }

    printf("reuse = %d\n", reuse);        // 1,表示已经设置端口号快速重用了


    return 0;
}

二、单播

就是实现一对一的通信,我们之前所学的TCP或UDP通信方式都是使用的是单播

发送端和接收端是确定的

三、多点通信

1> 实现主机之间的一对多的通信,一个发送端可以对应多个接收端

2> 对于接收端而言,无论愿不愿意接收,都会收到消息

3> 只能基于UDP实现多点通信

4> 实现多点通信的方式:广播、组播

3.1 广播

1> 能够实现主机的一对多的通信

2> 在当前网络下的所有主机都能接收到广播消息

3> 对于广播的发送端套接字而言,需要将其设置成允许广播的状态

4> 广播地址:网络号 + 255

5> 广播消息不允许穿过路由器

6> 广播分为发送端和接收端

7> 广播的发送端流程----> 类似于UDP的客户端

cpp 复制代码
1、socket:创建用于通信的套接字文件描述符
2、setsockopt:设置当前套接字允许广播, level:SOL_SOCKET      optname:SO_BROADCAST     optval: int
3、bind:可绑定也可以不绑定
4、发送广播消息:sendto
        目的IP地址:广播地址
        目的Port:与接收端保持一致
5、close:关闭套接字
cpp 复制代码
#include<myhead.h>
#define IP "192.168.125.255"          //广播地址
#define PORT 6789                    //端口号

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

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


    //3、发送消息
    //3.1 填充对端地址信息结构体
    struct sockaddr_in rin;
    rin.sin_family = AF_INET;
    rin.sin_port = htons(PORT);
    rin.sin_addr.s_addr = inet_addr(IP);

    char sbuf[128] = "";
    while(1)
    {
        //从终端获取数据
        printf("请输入>>>");
        fgets(sbuf, sizeof(sbuf), stdin);
        sbuf[strlen(sbuf)-1] = 0;

        //将数据广播出去
        sendto(sfd, sbuf, strlen(sbuf), 0, (struct sockaddr*)&rin, sizeof(rin));
        printf("发送成功\n");
    }

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

    return 0;
}

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

1、socket:创建用于通信的套接字文件描述符 2、bind:必须绑定 IP地址:广播地址 Port:与发送端保持一致 3、recvfrom:接收广播消息 4、close:关闭套接字

cpp 复制代码
#include<myhead.h>
#define IP "192.168.125.255"          //广播地址
#define PORT 6789                    //端口号

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

    //2、绑定ip和端口号
    //2.1 填充地址信息结构体
    struct sockaddr_in rin;
    rin.sin_family = AF_INET;
    rin.sin_port = htons(PORT);
    rin.sin_addr.s_addr = inet_addr(IP);

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

    //3、接受消息
    char rbuf[128] = "";
    while(1)
    {
        bzero(rbuf, sizeof(rbuf));         //清空容器
        //读取数据
        recvfrom(rfd, rbuf, sizeof(rbuf), 0, NULL, NULL);
        //recv(rfd, rbuf, sizeof(rbuf), 0);

        printf("收到广播消息:%s\n", rbuf);
    }

    //4、关闭套接字
    close(rfd);

    return 0;
}

3.2 组播

1> 组播也是实现一对多的通信

2> 组播地址:D类网络---> [224.0.0.0 -- 239.255.255.255]

3> 组播也分为发送端和接收端,对于接收端而言,要加入多播组后,才能收到组播消息

4> 组播的发送端 ----> 类似于UDP的客户端

cpp 复制代码
1、socket:创建用于通信的套接字文件描述符
2、bind:可绑定也可以不绑定
3、发送广播消息:sendto
        目的IP地址:组播地址
        目的Port:与接收端保持一致
4、close:关闭套接字
cpp 复制代码
#include<myhead.h>


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

    //3、发送消息
    //3.1 填充对端地址信息结构体
    struct sockaddr_in rin;
    rin.sin_family = AF_INET;
    rin.sin_port = htons(5555);
    rin.sin_addr.s_addr = inet_addr("224.1.1.1");  //组播地址

    char sbuf[128] = "";
    while(1)
    {
        //从终端获取数据
        printf("请输入>>>");
        fgets(sbuf, sizeof(sbuf), stdin);
        sbuf[strlen(sbuf)-1] = 0;

        //将数据广播出去
        sendto(sfd, sbuf, strlen(sbuf), 0, (struct sockaddr*)&rin, sizeof(rin));
        printf("发送成功\n");
    }

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

    return 0;
}

5> 组播的接收端 ----> 类似于UDP的服务器端

cpp 复制代码
1、socket:创建用于通信的套接字文件描述符
2、setsockopt:将当前套接字加入多播组, level:IPPROTO_IP    optname:IP_ADD_MEMBERSHIP    optval:struct ip_mreq
                 struct ip_mreqn {
                               struct in_addr imr_multiaddr;    //广播地址
                               struct in_addr imr_address;      //主机ip
                               int            imr_ifindex;      //网卡编号   可以通过指令 ip ad 进行查看当前网卡设备的编号
                           };

3、bind:必须绑定
        IP地址:广播地址
        Port:与发送端保持一致
4、recvfrom:接收广播消息
5、close:关闭套接字
cpp 复制代码
#include<myhead.h>

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

    //2、加入多播组
    //2.1 创建结构体变量
    struct ip_mreqn imq;
    imq.imr_multiaddr.s_addr = inet_addr("224.1.1.1");    //广播地址
    imq.imr_address.s_addr = inet_addr("192.168.125.221");  //主机IP
    imq.imr_ifindex = 2;            //网卡索引
    //2.2 设置套接字
    if(setsockopt(rfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imq, sizeof(imq)) == -1)
    {
        perror("setsockopt error");
        return -1;
    }
    printf("加入多播组成功\n");

    //3、绑定
    //3.1 填充地址信息结构体
    struct sockaddr_in rin;
    rin.sin_family = AF_INET;
    rin.sin_port = htons(5555);         //端口号
    rin.sin_addr.s_addr = inet_addr("224.1.1.1");   //组播IP

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


    //4、接受消息
    char rbuf[128] = "";
    while(1)
    {
        bzero(rbuf, sizeof(rbuf));         //清空容器
        //读取数据
        recvfrom(rfd, rbuf, sizeof(rbuf), 0, NULL, NULL);
        //recv(rfd, rbuf, sizeof(rbuf), 0);

        printf("收到组播消息:%s\n", rbuf);
    }

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

    return 0;
}
相关推荐
丶Darling.11 分钟前
LeetCode Hot100 | Day1 | 二叉树:二叉树的直径
数据结构·c++·学习·算法·leetcode·二叉树
5967851542 小时前
DotNetty ChannelRead接收数据为null
tcp/ip·c#
z樾2 小时前
Github界面学习
学习
芯橦2 小时前
【瑞昱RTL8763E】音频
单片机·嵌入式硬件·mcu·物联网·音视频·visual studio code·智能手表
道爷我悟了3 小时前
Vue入门-指令学习-v-html
vue.js·学习·html
hgdlip3 小时前
如何快速切换电脑的ip地址
网络·tcp/ip·电脑
计算机学姐4 小时前
基于SpringBoot+Vue的在线投票系统
java·vue.js·spring boot·后端·学习·intellij-idea·mybatis
彤银浦4 小时前
python学习记录7
python·学习
少女忧4 小时前
51单片机学习第六课---B站UP主江协科技
科技·学习·51单片机
程序员-珍4 小时前
虚拟机ip突然看不了了
linux·网络·网络协议·tcp/ip·centos