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

使用getifaddrs获取Linux CAN接口报文统计数据失败如何解决

问题原因

你遇到的是Debian Jessie对应glibc 2.19版本的getifaddrs实现缺陷:CAN总线接口的地址族为AF_CAN,旧版glibc不会为这类非常规网络接口生成AF_PACKET类型的地址条目,所以你拿到的ifa_addr为NULL,无法通过该接口获取统计数据。而ifconfig是通过更底层的rtnetlink接口获取统计数据,不受该问题影响。

正确获取CAN接口统计的两种方法

方法1:读取sysfs文件(推荐,实现简单)

Linux下所有网络接口的统计数据都暴露在sysfs的/sys/class/net/<接口名>/statistics/目录下,每个统计项对应一个纯文本文件,直接读取即可,不需要依赖系统调用兼容性:

  • 收包数:/sys/class/net/can0/statistics/rx_packets
  • 发包数:/sys/class/net/can0/statistics/tx_packets
  • 接收丢包数:/sys/class/net/can0/statistics/rx_dropped
  • 发送错误数:/sys/class/net/can0/statistics/tx_errors
  • 接收字节数:/sys/class/net/can0/statistics/rx_bytes
  • 发送字节数:/sys/class/net/can0/statistics/tx_bytes

C++读取示例:

#include <fstream>
#include <string>
#include <iostream>

unsigned long read_sysfs_stat(const std::string& iface, const std::string& stat) {
    std::string path = "/sys/class/net/" + iface + "/statistics/" + stat;
    std::ifstream file(path);
    unsigned long val = 0;
    if (file.is_open()) {
        file >> val;
        file.close();
    }
    return val;
}

int main() {
    std::cout << "can0 rx packets: " << read_sysfs_stat("can0", "rx_packets") << std::endl;
    std::cout << "can0 dropped: " << read_sysfs_stat("can0", "rx_dropped") << std::endl;
    std::cout << "can0 tx packets: " << read_sysfs_stat("can0", "tx_packets") << std::endl;
    return 0;
}

方法2:使用rtnetlink套接字

如果需要批量获取多个接口的统计数据,可以使用netlink套接字和内核交互获取rtnl_link_stats结构体,和ifconfig的实现逻辑一致,示例代码如下:

#include <asm/types.h>
#include <linux/if_link.h>
#include <linux/rtnetlink.h>
#include <sys/socket.h>
#include <net/if.h>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>

int main() {
    int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    if (sock < 0) {
        perror("socket");
        return 1;
    }

    struct {
        struct nlmsghdr nh;
        struct ifinfomsg ifi;
        char buf[1024];
    } req;

    memset(&req, 0, sizeof(req));
    req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
    req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
    req.nh.nlmsg_type = RTM_GETLINK;
    req.ifi.ifi_family = AF_UNSPEC;

    if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
        perror("send");
        close(sock);
        return 1;
    }

    char buf[8192];
    ssize_t len = recv(sock, buf, sizeof(buf), 0);
    if (len < 0) {
        perror("recv");
        close(sock);
        return 1;
    }

    for (struct nlmsghdr* nh = (struct nlmsghdr*)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) {
        if (nh->nlmsg_type == NLMSG_DONE) break;
        if (nh->nlmsg_type != RTM_NEWLINK) continue;

        struct ifinfomsg* ifi = (struct ifinfomsg*)NLMSG_DATA(nh);
        char ifname[IFNAMSIZ];
        if_indextoname(ifi->ifi_index, ifname);

        struct rtattr* rta = IFLA_RTA(ifi);
        int rtl = RTM_PAYLOAD(nh);
        for (; RTA_OK(rta, rtl); rta = RTA_NEXT(rta, rtl)) {
            if (rta->rta_type == IFLA_STATS) {
                struct rtnl_link_stats* stats = (struct rtnl_link_stats*)RTA_DATA(rta);
                printf("接口 %s 收包数: %u 丢包数: %u 发包数: %u\n", 
                       ifname, stats->rx_packets, stats->rx_dropped, stats->tx_packets);
            }
        }
    }

    close(sock);
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 20:39:03