c++广播通讯的实现

概念大家都很清楚,不赘述。

广播必然用UDP这套东西。

setsockopt() 函数及其在广播中的应用:

在 C++ 网络编程中,setsockopt() 函数用于设置套接字选项,这些选项可以控制套接字的各种行为。对于广播通信,我们特别关心的是 SO_BROADCAST 选项,它允许套接字发送广播消息。

setsockopt() 函数原型

cpp 复制代码
int setsockopt(int sockfd, int level, int option_name, const void *option_value, socklen_t option_len);
  • sockfd:要设置选项的套接字描述符。
  • level:指定选项所在的协议层。对于大多数套接字选项,这一层是 SOL_SOCKET,表示选项与套接字层本身相关。
  • option_name:要设置的选项的名称。对于广播选项,这是 SO_BROADCAST
  • option_value:指向一个变量的指针,该变量包含要设置的选项的值。对于 SO_BROADCAST,这个值通常是一个整数,非零表示启用广播,零表示禁用(尽管禁用广播通常不是必需的,因为默认情况下它可能是禁用的,除非特别启用)。
  • option_lenoption_value 指向的变量的长度,以字节为单位。对于 SO_BROADCAST,这通常是 sizeof(int)

SO_BROADCAST 选项

  • 作用:允许套接字发送广播消息。广播消息是发送到网络上的所有主机的消息,这些主机都监听特定的广播地址和端口。
  • 默认值:在大多数系统上,套接字默认不允许发送广播消息,必须显式启用。
  • 使用场景:当您希望向网络上的多个主机发送相同的信息时,广播非常有用。例如,在局域网中查找服务或设备时。

框架示例代码

以下是如何在 C++ 中使用 setsockopt() 启用 SO_BROADCAST 选项的示例代码:

cpp 复制代码
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdio.h>

int main() {
    int sockfd;
    int broadcastEnable = 1; // 启用广播

    // 创建 UDP 套接字
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0) {
        perror("socket creation failed");
        return 1;
    }

    // 启用广播选项
    if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable)) < 0) {
        perror("setsockopt(SO_BROADCAST) failed");
        close(sockfd);
        return 1;
    }

    // ... 在这里发送广播消息 ...

    // 关闭套接字
    close(sockfd);
    return 0;
}

在这个例子中,我们首先创建了一个 UDP 套接字,然后使用 setsockopt() 函数启用了 SO_BROADCAST 选项。之后,我们可以使用 sendto() 函数发送广播消息。最后,我们关闭了套接字。

完整的广播的过程:

在 C++ 中使用套接字(socket)进行广播通信,通常涉及以下几个步骤:

  1. 创建套接字 :使用 socket() 函数创建一个 UDP 套接字,因为 UDP 支持广播。
  2. 设置广播选项 :使用 setsockopt() 函数启用广播选项。
  3. 绑定套接字 (可选):如果你希望绑定到特定的端口和/或 IP 地址,可以使用 bind() 函数。
  4. 发送广播消息 :使用 sendto() 函数将消息发送到广播地址(通常是 255.255.255.255)。

下面是一个简单的示例代码,展示了如何在 C++ 中使用套接字进行广播通信:

cpp 复制代码
#include <iostream>
#include <cstring>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PORT 8080
#define BROADCAST_IP "255.255.255.255"
#define BUFFER_SIZE 1024

int main() {
    int sockfd;
    struct sockaddr_in broadcastAddr;
    const char *message = "Hello, this is a broadcast message!";
    char buffer[BUFFER_SIZE];

    // 创建 UDP 套接字
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    int broadcastEnable = 1;
    // 启用广播选项
    if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable)) < 0) {
        perror("setsockopt(SO_BROADCAST) failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // 设置广播地址和端口
    memset(&broadcastAddr, 0, sizeof(broadcastAddr));
    broadcastAddr.sin_family = AF_INET;
    broadcastAddr.sin_addr.s_addr = inet_addr(BROADCAST_IP);
    broadcastAddr.sin_port = htons(PORT);

    // 发送广播消息
    if (sendto(sockfd, message, strlen(message), MSG_CONFIRM, (const struct sockaddr*)&broadcastAddr, sizeof(broadcastAddr)) < 0) {
        perror("sendto failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    std::cout << "Broadcast message sent: " << message << std::endl;

    // 关闭套接字
    close(sockfd);

    return 0;
}

注意事项

  1. 权限 :在某些操作系统(如 Linux)上,发送广播消息可能需要管理员权限。如果遇到权限问题,可以尝试以 root 用户运行程序,或者使用 sudo 命令。
  2. 防火墙:确保防火墙设置允许广播消息的发送和接收。
  3. 网络配置:确保网络配置允许广播通信。

接收广播消息

要接收广播消息,你需要创建一个监听特定端口和地址(通常是 INADDR_ANY)的套接字,然后等待接收数据。以下是一个简单的接收广播消息的示例:

cpp 复制代码
#include <iostream>
#include <cstring>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PORT 8080
#define BUFFER_SIZE 1024

int main() {
    int sockfd;
    struct sockaddr_in serverAddr, clientAddr;
    socklen_t addrLen = sizeof(clientAddr);
    char buffer[BUFFER_SIZE];

    // 创建 UDP 套接字
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    // 绑定套接字到指定端口
    memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = INADDR_ANY;
    serverAddr.sin_port = htons(PORT);

    if (bind(sockfd, (const struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
        perror("bind failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // 接收广播消息
    ssize_t numBytes = recvfrom(sockfd, buffer, BUFFER_SIZE - 1, MSG_WAITALL, (struct sockaddr*)&clientAddr, &addrLen);
    if (numBytes < 0) {
        perror("recvfrom failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    buffer[numBytes] = '\0';
    std::cout << "Received broadcast message: " << buffer << std::endl;

    // 关闭套接字
    close(sockfd);

    return 0;
}

这个接收程序将监听指定的端口,并打印接收到的广播消息。确保接收程序和发送程序在相同的网络环境中运行,并且端口号匹配。

这里服务器套接字被绑定到了指定的端口(PORT,即8080),并且它准备好接收来自任何IP地址的数据报(因为serverAddr.sin_addr.s_addr被设置为INADDR_ANY)。由于套接字是UDP类型的,并且没有设置特定的广播接收选项(实际上,对于UDP套接字来说,接收广播消息是默认启用的),因此该套接字能够接收发送到该端口上的任何UDP数据报,包括广播消息。

然而,代码本身并没有特别指定它只接收来自某个特定广播地址的消息。当recvfrom()函数被调用时,它会阻塞(除非套接字被设置为非阻塞模式),直到有数据报到达绑定的端口。一旦数据报到达,recvfrom()会填充clientAddr结构体以反映发送方的IP地址和端口号。

要知道广播消息的实际来源广播地址,您可以检查clientAddr.sin_addr字段。这个字段包含了发送方的IP地址,如果这是一个广播消息,那么它应该是您网络上的广播地址(比如255.255.255.255对于本地广播,或者是子网特定的广播地址,比如192.168.1.255对于子网192.168.1.0/24)。但是,请注意,如果发送方不在同一个子网内,并且是通过路由器发送的广播消息(这通常是不被允许的,因为广播消息通常不会跨子网路由),那么clientAddr可能会显示发送方的实际IP地址,而不是广播地址。

在实际应用中,如果您想要接收特定广播地址上的消息,您通常需要在网络上有一个已知的广播地址,并且您的应用程序需要知道这个地址。然而,由于UDP广播的本地性质,您的应用程序通常只能接收到来自同一子网内的广播消息,除非有特殊的路由配置允许跨子网的广播。

另外,值得注意的是,在现代网络环境中,由于安全和维护方面的原因,许多网络都配置为不允许或限制广播消息的传播。因此,在实际部署基于UDP广播的应用程序时,您可能需要考虑这些因素。

相关推荐
‘’林花谢了春红‘’12 分钟前
计算机网络习题(第5章 网络层 第6章 传输层)
网络·计算机网络
哎呦不错哦.18 分钟前
简单园区网拓扑实验
网络·智能路由器
咕德猫宁丶5 小时前
探秘Xss:原理、类型与防范全解析
java·网络·xss
黑子哥呢?5 小时前
Linux---防火墙端口设置(firewalld)
linux·服务器·网络
hellojackjiang20116 小时前
开源轻量级IM框架MobileIMSDK的鸿蒙NEXT客户端库已发布
网络·即时通讯·im开发·mobileimsdk-鸿蒙端
WebDeveloper20017 小时前
如何使用美国域名中心US Domain Center和WordPress创建商业网站
运维·服务器·css·网络·html
车载诊断技术8 小时前
电子电气架构 --- 什么是EPS?
网络·人工智能·安全·架构·汽车·需求分析
KevinRay_8 小时前
Python超能力:高级技巧让你的代码飞起来
网络·人工智能·python·lambda表达式·列表推导式·python高级技巧
2301_819287129 小时前
ce第六次作业
linux·运维·服务器·网络
CIb0la9 小时前
GitLab 停止为中国区用户提供 GitLab.com 账号服务
运维·网络·程序人生