You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在以太网中监听MAC地址?C++收发程序实现及应用场景答疑

以太网无IP/端口通信:运作逻辑、实现方案与应用场景

一、以太网替代互联网的核心运作逻辑

当脱离互联网改用以太网直接通信时,无需依赖IP地址和端口,完全靠MAC地址实现设备识别与数据传输:

  • 以太网属于链路层协议,每个数据帧的头部会携带目标MAC地址和源MAC地址;
  • 局域网内的交换机维护着MAC地址表,会根据目标MAC将帧转发到对应端口;
  • 网卡收到帧后,会先检查目标MAC是否与自身MAC匹配(或是广播MAC),匹配则接收并向上传递,否则直接丢弃;
  • 这种模式跳过了IP层的路由、端口映射等开销,直接实现设备级的点对点/广播通信。

二、以太网的实际应用场景

  1. 工业控制系统:PLC、工业机器人等设备对延迟和可靠性要求极高,直接用以太网链路层通信可避免IP协议栈的额外开销,保证实时性;
  2. 局域网设备发现:打印机、智能家居设备的自动探测,通常通过广播MAC帧来寻找同网段内的设备;
  3. 网络调试与监控:Wireshark等抓包工具底层就是监听以太网帧,用于排查链路层故障(比如网卡冲突、帧丢失);
  4. 嵌入式设备通信:单片机、物联网网关等资源有限的设备,省去IP协议栈的占用,直接通过MAC地址完成短距离局域网内的数据交互;
  5. 特殊安全场景:某些封闭局域网内,禁用IP协议可减少网络攻击面,仅通过MAC地址实现设备间的可控通信。

三、C++实现MAC地址通信(Linux平台)

1. 向指定MAC地址发送数据的客户端

需要创建原始套接字来构造并发送以太网帧,代码示例如下:

#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <unistd.h>
#include <arpa/inet.h>

using namespace std;

// 字符串MAC转字节数组
void mac_str_to_bytes(const char* mac_str, unsigned char* mac_bytes) {
    sscanf(mac_str, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
           &mac_bytes[0], &mac_bytes[1], &mac_bytes[2],
           &mac_bytes[3], &mac_bytes[4], &mac_bytes[5]);
}

int main() {
    // 创建原始套接字
    int sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (sockfd < 0) {
        perror("socket create failed");
        return -1;
    }

    // 指定本地网卡(替换为你的网卡名称,如eth0、ens33)
    const char* if_name = "eth0";
    int if_index = if_nametoindex(if_name);
    if (if_index == 0) {
        perror("get interface index failed");
        close(sockfd);
        return -1;
    }

    // 构造以太网帧
    unsigned char eth_frame[ETH_FRAME_LEN] = {0};
    const char* dest_mac_str = "00:11:22:33:44:55"; // 目标设备MAC
    const char* src_mac_str = "aa:bb:cc:dd:ee:ff";  // 本地网卡MAC
    unsigned char dest_mac[6], src_mac[6];
    
    mac_str_to_bytes(dest_mac_str, dest_mac);
    mac_str_to_bytes(src_mac_str, src_mac);
    
    // 填充帧头部:目标MAC、源MAC、帧类型(自定义0x1234)
    memcpy(eth_frame, dest_mac, 6);
    memcpy(eth_frame + 6, src_mac, 6);
    unsigned short eth_type = htons(0x1234);
    memcpy(eth_frame + 12, &eth_type, 2);

    // 填充负载数据
    const char* payload = "Direct MAC communication test";
    int payload_len = strlen(payload);
    memcpy(eth_frame + 14, payload, payload_len);

    // 绑定套接字到指定网卡
    struct sockaddr_ll sock_addr = {0};
    sock_addr.sll_family = AF_PACKET;
    sock_addr.sll_protocol = htons(ETH_P_ALL);
    sock_addr.sll_ifindex = if_index;
    sock_addr.sll_halen = ETH_ALEN;
    memcpy(sock_addr.sll_addr, dest_mac, 6);

    // 发送帧
    int send_len = sendto(sockfd, eth_frame, 14 + payload_len, 0,
                          (struct sockaddr*)&sock_addr, sizeof(sock_addr));
    if (send_len < 0) {
        perror("sendto failed");
        close(sockfd);
        return -1;
    }

    cout << "Sent " << send_len << " bytes to MAC: " << dest_mac_str << endl;
    close(sockfd);
    return 0;
}

编译运行:

g++ send_mac.cpp -o send_mac
sudo ./send_mac  # 需root权限,原始套接字需要管理员权限

2. MAC地址监听程序

监听指定网卡上的以太网帧,筛选出目标MAC匹配的帧:

#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <unistd.h>
#include <arpa/inet.h>

using namespace std;

// 比较两个MAC地址是否相等
bool mac_equal(const unsigned char* mac1, const unsigned char* mac2) {
    return memcmp(mac1, mac2, 6) == 0;
}

// 字节数组MAC转字符串
void mac_bytes_to_str(const unsigned char* mac_bytes, char* mac_str) {
    sprintf(mac_str, "%02x:%02x:%02x:%02x:%02x:%02x",
            mac_bytes[0], mac_bytes[1], mac_bytes[2],
            mac_bytes[3], mac_bytes[4], mac_bytes[5]);
}

int main() {
    // 创建原始套接字
    int sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (sockfd < 0) {
        perror("socket create failed");
        return -1;
    }

    // 指定监听网卡
    const char* if_name = "eth0";
    int if_index = if_nametoindex(if_name);
    if (if_index == 0) {
        perror("get interface index failed");
        close(sockfd);
        return -1;
    }

    // 绑定套接字到网卡
    struct sockaddr_ll sock_addr = {0};
    sock_addr.sll_family = AF_PACKET;
    sock_addr.sll_protocol = htons(ETH_P_ALL);
    sock_addr.sll_ifindex = if_index;

    if (bind(sockfd, (struct sockaddr*)&sock_addr, sizeof(sock_addr)) < 0) {
        perror("bind failed");
        close(sockfd);
        return -1;
    }

    // 要监听的目标MAC(替换为你的网卡MAC)
    const char* target_mac_str = "aa:bb:cc:dd:ee:ff";
    unsigned char target_mac[6];
    sscanf(target_mac_str, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
           &target_mac[0], &target_mac[1], &target_mac[2],
           &target_mac[3], &target_mac[4], &target_mac[5]);

    cout << "Listening for frames to MAC: " << target_mac_str << " on " << if_name << endl;

    // 循环接收帧
    unsigned char eth_frame[ETH_FRAME_LEN];
    while (true) {
        int recv_len = recvfrom(sockfd, eth_frame, ETH_FRAME_LEN, 0, nullptr, nullptr);
        if (recv_len < 0) {
            perror("recvfrom failed");
            close(sockfd);
            return -1;
        }

        // 解析帧头部
        unsigned char* dest_mac = eth_frame;
        unsigned char* src_mac = eth_frame + 6;
        unsigned short eth_type = ntohs(*(unsigned short*)(eth_frame + 12));
        unsigned char* payload = eth_frame + 14;
        int payload_len = recv_len - 14;

        // 筛选目标MAC匹配或广播的帧
        if (mac_equal(dest_mac, target_mac) || mac_equal(dest_mac, (unsigned char*)"\xff\xff\xff\xff\xff\xff")) {
            char src_mac_str[18];
            mac_bytes_to_str(src_mac, src_mac_str);
            cout << "\nReceived from: " << src_mac_str << endl;
            cout << "Frame type: 0x" << hex << eth_type << dec << endl;
            cout << "Payload (" << payload_len << " bytes): " << string((char*)payload, payload_len) << endl;
        }
    }

    close(sockfd);
    return 0;
}

编译运行:

g++ listen_mac.cpp -o listen_mac
sudo ./listen_mac

四、Windows平台实现说明

Windows下没有PF_PACKET套接字,若要实现链路层通信,可通过以下两种方式:

  1. 使用WinPcap或Npcap库,提供了跨平台的链路层操作API;
  2. 调用Windows原生的WSASocket创建原始套接字,设置AF_LINK地址族,但操作比Linux复杂,且需要管理员权限。

内容的提问来源于stack exchange,提问作者Joseph Conrad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 04:10:35