【嵌入式linux】网口和USB热插拔检测

server/2025/3/18 3:51:43/

在Linux常常需要对网口和USB等外设接口进行插拔检测,从而执行部分初始化操作。下面简要介绍Linux的Netlink机制,并在C程序中使用Linux的Netlink机制完成网口和USB口插拔检测

Netlink 是 Linux 内核与用户空间进程通信的一种机制,主要用于内核模块和用户程序之间的数据传输。它比传统的通信方式(如 ioctl、procfs、sysfs)更灵活高效。
一、主要特点
双向通信:支持内核与用户空间的双向数据传输。
多协议支持:通过不同的协议类型(如 NETLINK_ROUTE、NETLINK_SOCK_DIAG)满足多种通信需求。
多播支持:允许一个消息同时发送给多个接收者。
异步通信:支持异步消息传递,适合事件驱动场景。
二、使用场景
网络配置:如 iproute2 工具通过 Netlink 配置网络接口和路由。
防火墙和策略路由:如 iptables 和 nftables 使用 Netlink 配置规则。
设备管理:如 udev 通过 Netlink 监控设备事件。
三、基本使用步骤
1.创建套接字:用户空间使用 socket() 创建 Netlink 套接字。

int sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);

2.绑定地址:绑定 Netlink 地址。

struct sockaddr_nl addr;
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid(); // 通常使用进程ID
bind(sock_fd, (struct sockaddr*)&addr, sizeof(addr));

3.发送和接收消息:使用 sendmsg() 和 recvmsg() 进行消息传递。
4.处理消息:解析和处理接收到的消息。

Demo1:使用Netlink实现网口热插拔。(ZYNQ-7020平台,linux内核为4.19)


#include <sys/socket.h>
#include <linux/if.h>
#include <linux/rtnetlink.h>
#include <linux/netlink.h>
typedef void (*network_status_callback)(char *eth_name,int status) ;
void network_link_monitor(network_status_callback arg)
{int sock;int ret;struct sockaddr_nl sa;int len=4096;char buf[4096]={0};struct nlmsghdr *nh;struct ifinfomsg  *ifinfo;struct rtattr *attr;network_status_callback nm=arg;int i;memset(&sa,0,sizeof(sa));sa.nl_family=AF_NETLINK;sa.nl_groups=RTNLGRP_LINK;//sa.nl_pid=getpid();//创建套接字和绑定Netlink地址,这里使用NETLINK_ROUTEsock=socket(AF_NETLINK,SOCK_RAW,NETLINK_ROUTE);if(sock<0)printf("socket err %d\n",__LINE__);setsockopt(sock,SOL_SOCKET,SO_RCVBUF,&len,sizeof(len));if(bind(sock,(struct sockaddr*)&sa,sizeof(sa))<0)printf("bind err %d\n",__LINE__);//阻塞接收内核的Netlink消息,可根据应用需求使用非阻塞IO读while((ret=read(sock,buf,sizeof(buf)))>0){for(nh=(struct nlmsghdr*)buf;NLMSG_OK(nh,ret);nh=NLMSG_NEXT(nh,ret)){//解析和处理接收到的内核消息if(nh->nlmsg_type==NLMSG_DONE)break;else if(nh->nlmsg_type==NLMSG_ERROR){printf("read err %d\n",__LINE__);return ;}else if (nh->nlmsg_type!=RTM_NEWLINK){printf("nlmsg_type err %d\n",__LINE__);continue;}ifinfo=NLMSG_DATA(nh);//printf("%u : %s \n",ifinfo->ifi_index,(ifinfo->ifi_flags&IFF_LOWER_UP)?"UP":"DOWN");attr=(struct rtattr*)(((char*)nh)+NLMSG_SPACE(sizeof(*ifinfo)));len=nh->nlmsg_len-NLMSG_SPACE(sizeof(*ifinfo));for(;RTA_OK(attr,len);attr=RTA_NEXT(attr,len)){if(attr->rta_type==IFLA_IFNAME){//执行热插拔检测回调函数//printf("%s : %s\n",(char*)RTA_DATA(attr),(ifinfo->ifi_flags&IFF_LOWER_UP)?"up":"down");if(ifinfo->ifi_flags&IFF_LOWER_UP)nm((char*)RTA_DATA(attr),LINK_UP);elsenm((char*)RTA_DATA(attr),LINK_DOWN);break;}}}}
}/*
网络插拔检测回调
*/
void monitor_callback(char *eth_name,int status)//status--1 up
{printf("%s %s\n",eth_name,status?"up":"down");
}int main()
{printf("net test\n");network_link_monitor(monitor_callback);while(1)sleep(1);    return 0;
}

编译Demo生成net_test拷贝到板子上
测试结果:重复插拔网口可看到内核打印信息和应用程序打印网口up和down信息
在这里插入图片描述
Demo2:使用Netlink实现USB口热插拔。(ZYNQ-7020平台,linux内核为4.19)

static void usb_host_thread(void *arg)
{char rcv_buf[32]={0};int link_status=0;int ret=0;//判断USB口初始拔插状态ret=usb_exec(USB_HOST_CMD);if(ret==0)link_status=1;elselink_status=0;struct sockaddr_nl client;struct timeval tv;int CppLive,rcvlen;fd_set fds;int buffersize=1024;//创建套接字和绑定Netlink地址,这里使用NETLINK_KOBJECT_UEVENTCppLive=socket(AF_NETLINK,SOCK_RAW,NETLINK_KOBJECT_UEVENT);if(CppLive<0){printf("socket err %d\n",__LINE__);return;}memset(&client,0,sizeof(client));client.nl_family=AF_NETLINK;//client.nl_pid=getpid();client.nl_groups=1;setsockopt(CppLive,SOL_SOCKET,SO_RCVBUF,&buffersize,sizeof(buffersize));bind(CppLive,(struct sockaddr*)&client,sizeof(client));while(1){char buf[2048]={0};/*FD_ZERO(&fds);FD_SET(CppLive,&fds);tv.tv_sec=0;tv.tv_usec=100 * 1000;ret=select(CppLive+1,&fds,NULL,NULL,&tv);if(ret<0){printf("select err %d\n",__LINE__);continue;}if(!(ret>0 && FD_ISSET(CppLive, &fds))){printf("select err %d\n",__LINE__);continue;}*/  //阻塞接收内核的Netlink消息,可根据应用需求使用非阻塞IO读rcvlen=recv(CppLive,buf,sizeof(buf),0);if(rcvlen > 0){//解析和处理接收到的内核消息//printf("%s\n",buf);if(strstr(buf,"add")!=NULL){if(link_status==0){((void (*)(int))arg)(1);}link_status=1;}else if(strstr(buf,"remove")!=NULL){if(link_status==1){((void (*)(int))arg)(0);}link_status=0;}}}}void callback(int status)
{if(status==1)printf("usb host up\n");if(status==0)printf("usb host down\n");
}int main()
{printf("usb test\n");usb_host_monitor(callback);while(1)sleep(1);    return 0;
}

编译Demo生成usb_test拷贝到板子上
测试结果:重复插拔USB host口可看到应用程序打印USB口的up和down信息
在这里插入图片描述


http://www.ppmy.cn/server/175851.html

相关文章

STM32 - 在机器人领域,LL库相比HAL优势明显

在机器人控制器、电机控制器等领域的开发&#xff0c;需要高实时性、精细化控制或者对代码执行效率、占用空间有较高要求。所以&#xff0c;大家常用的HAL库明显不符合要求。再加上&#xff0c;我们学习一门技术&#xff0c;一定要学会掌握底层的原理。MCU开发的底层就是寄存器…

MongoDB 和 Elasticsearch的区别、优缺点对比,以及选型建议

MongoDB 和 Elasticsearch 在存储和搜索方面各有特点&#xff0c;适用于不同的场景。以下是它们的区别、优缺点对比&#xff0c;以及选型建议。 1. 概述 MongoDB&#xff1a;分布式 NoSQL 文档数据库&#xff0c;基于 BSON&#xff08;类似 JSON&#xff09;的文档存储&#x…

R语言:初始环境配置

文章目录 R语言的配置URL和种子 R语言的配置 在R中安装languageserver 包&#xff1a;&#xff08;直接在R.exe中运行即可&#xff09; install.packages("languageserver")关于jupyter notebook如何编写R语言&#xff1a; &#xff08;好像每种jupyter notebook支…

大数据平台性能调优:从入门到精通

大数据平台性能调优:从入门到精通 前言:大数据平台为何需要调优? 大数据平台承载着海量数据存储、计算、分析的任务,其性能直接影响到数据处理效率、查询响应速度和资源利用率。然而,在实际应用中,许多企业发现自己的大数据平台运行缓慢、资源消耗巨大、作业执行时间过…

TDengine SQL 函数

单行函数 数学函数 ABSACOSASINATANCEILCOSDEGREESEXPFLOORGREATESTLEASTLNLOGMODPIPOWRADIANSRANDROUNDSIGNSINSQRTTANTRUNCATE 字符串函数 ASCIICHARCHAR_LENGTHCONCATCONCAT_WSLENGTHLOWERLTRIMPOSITIONREPEATREPLACERTRIMSUBSTRING/SUBSTRSUBSTRING_INDEXTRIMUPPER 转换函数…

深入理解 HTML 中的<div>和元素:构建网页结构与样式的基石

一、引言 在 HTML 的世界里&#xff0c;<div>和元素虽看似普通&#xff0c;却扮演着极为关键的角色。它们就像网页搭建过程中的万能积木&#xff0c;能够将各种 HTML 元素巧妙地组合起来&#xff0c;无论是构建页面布局&#xff0c;还是对局部内容进行样式调整&#xff…

【从零开始学习计算机科学】数据库系统(八)数据库的备份和恢复

【从零开始学习计算机科学】数据库系统(八)数据库的备份和恢复 备份和恢复事务故障系统故障磁盘故障其他故障故障的恢复日志日志缓冲区事务故障的恢复系统故障的恢复系统故障的恢复步骤检查点检查点的执行过程备份日志文件备份远程备份恢复策略事务故障恢复策略系统崩溃恢复策…

06kafka及异步通知文章上下架

1)自媒体文章上下架 需求分析 之前只是自媒体文章上下架&#xff0c;但是我要通知给文章 用feign会产生系统的耦合&#xff0c;用mq最好 2)kafka概述 消息中间件对比 特性ActiveMQRabbitMQRocketMQKafka开发语言javaerlangjavascala单机吞吐量万级万级10万级100万级时效性m…