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

求检测以太网链路通断状态的C语言实现方案及建议

C语言实现以太网链路状态检测方案

下面针对静态IP设备间以太网链路状态(UP/DOWN)检测需求,提供两种实用实现方式及注意事项:

方法一:通过ioctl轮询接口状态

这是兼容性较好的传统方案,通过SIOCGIFFLAGS命令获取接口标志位,判断物理链路是否连通。

代码示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/socket.h>

// 检测指定接口的链路状态:返回1表示UP,0表示DOWN,-1表示出错
int check_link_status(const char* ifname) {
    int sockfd;
    struct ifreq ifr;

    // 创建套接字(无需实际连接)
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0) {
        perror("socket failed");
        return -1;
    }

    memset(&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);

    // 获取接口标志
    if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
        perror("ioctl failed");
        close(sockfd);
        return -1;
    }

    close(sockfd);

    // IFF_UP表示接口已启用,IFF_RUNNING表示物理链路连通
    if ((ifr.ifr_flags & IFF_UP) && (ifr.ifr_flags & IFF_RUNNING)) {
        return 1;
    } else {
        return 0;
    }
}

int main(int argc, char* argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <interface-name>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    while (1) {
        int status = check_link_status(argv[1]);
        if (status == 1) {
            printf("Interface %s is UP\n", argv[1]);
        } else if (status == 0) {
            printf("Interface %s is DOWN\n", argv[1]);
        } else {
            fprintf(stderr, "Failed to check interface status\n");
            exit(EXIT_FAILURE);
        }
        sleep(2); // 每2秒轮询一次
    }

    return 0;
}

关键说明

  • IFF_UP:表示接口已被系统启用(如执行ifconfig up操作)
  • IFF_RUNNING:表示物理链路已连通(网线插好、链路协商成功)
  • 程序需要以root权限运行,否则ioctl调用会失败

方法二:通过Netlink套接字监听链路事件

轮询方式会持续占用系统资源,Netlink可以主动接收内核发送的链路状态变化事件,效率更高。

代码示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <net/if.h>

#define BUFFER_SIZE 4096

// 解析Netlink消息中的链路状态
void parse_link_status(struct nlmsghdr* nlh) {
    struct ifinfomsg* ifinfo;
    struct rtattr* rta;
    int rta_len;
    char ifname[IFNAMSIZ];
    int link_up = 0;

    ifinfo = NLMSG_DATA(nlh);
    rta = IFLA_RTA(ifinfo);
    rta_len = IFLA_PAYLOAD(nlh);

    // 提取接口名称和状态
    while (RTA_OK(rta, rta_len)) {
        if (rta->rta_type == IFLA_IFNAME) {
            strncpy(ifname, RTA_DATA(rta), IFNAMSIZ - 1);
            ifname[IFNAMSIZ - 1] = '\0';
        } else if (rta->rta_type == IFLA_OPERSTATE) {
            // IFLA_OPERSTATE返回的状态:IF_OPER_UP表示链路正常
            link_up = (*(unsigned int*)RTA_DATA(rta) == IF_OPER_UP);
        }
        rta = RTA_NEXT(rta, rta_len);
    }

    printf("Interface %s: %s\n", ifname, link_up ? "UP" : "DOWN");
}

int main() {
    int sockfd;
    struct sockaddr_nl sa;
    char buffer[BUFFER_SIZE];
    struct nlmsghdr* nlh;

    // 创建Netlink套接字
    sockfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    if (sockfd < 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    memset(&sa, 0, sizeof(sa));
    sa.nl_family = AF_NETLINK;
    sa.nl_groups = RTMGRP_LINK; // 订阅链路事件

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

    printf("Listening for link status changes...\n");

    while (1) {
        int len = recv(sockfd, buffer, BUFFER_SIZE, 0);
        if (len < 0) {
            perror("recv failed");
            close(sockfd);
            exit(EXIT_FAILURE);
        }

        // 遍历所有Netlink消息
        for (nlh = (struct nlmsghdr*)buffer; NLMSG_OK(nlh, len); nlh = NLMSG_NEXT(nlh, len)) {
            if (nlh->nlmsg_type == NLMSG_DONE) {
                break;
            } else if (nlh->nlmsg_type == NLMSG_ERROR) {
                perror("Netlink error");
                close(sockfd);
                exit(EXIT_FAILURE);
            } else if (nlh->nlmsg_type == RTM_NEWLINK || nlh->nlmsg_type == RTM_DELLINK) {
                parse_link_status(nlh);
            }
        }
    }

    close(sockfd);
    return 0;
}

关键说明

  • NETLINK_ROUTE:用于与内核路由子系统通信
  • RTMGRP_LINK:订阅链路状态变化事件
  • IFLA_OPERSTATE:获取接口的操作状态,IF_OPER_UP表示链路正常连通
  • 同样需要root权限运行,无需轮询,仅在状态变化时触发处理

实现建议

  • 权限问题:两种方案都需要root权限运行,普通用户无法访问网络接口的底层状态
  • 接口名称验证:确保传入的接口名称正确(如eth0、enp0s3等),可通过ip link命令查看系统接口列表
  • 错误处理:需完善错误处理逻辑,比如套接字创建失败、ioctl调用失败等场景
  • 轮询间隔:若使用轮询方式,间隔建议设为1-5秒,避免占用过多CPU资源
  • 跨平台兼容性:上述代码仅适用于Linux系统,Windows或BSD系统需使用对应平台API(如Windows的GetIfEntry2)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 13:05:26