Linux 热插拔识别

主要通过NETLINK实现,直接贴代码

hotplugmonitor.h

#ifndef HOTPLUGMONITOR_H
#define HOTPLUGMONITOR_H
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <sys/mount.h>
#include <iostream>
#include <string>
#include <sstream>
#include "typedef.h"
#include "ZeroMQ.h"
#include "globalinc.h"
using namespace std;

#define HOTPLUG_PUB_PORT 9997
#define EPOLL_FD_SIZE     3   //需要监听的fd个数
#define EPOLL_EVENT_SIZE  2
#define EPOLL_TIMEOUT     1000  //等待的超时时间,1000ms 也就是1秒

#ifndef KERNEL_UEVENT_LEN
#define KERNEL_UEVENT_LEN      (4*1024)
#endif

#define NODENAMEFOUND		1
#define PATIONNAMEFOUND		2
typedef struct
{
    int epoll_fd;              //epoll 对应的fd
    int uevent_fd;             //热插拔节点的sock 句柄
    pthread_t hotplug_thread;  //对应的线程
    int is_start;              //线程是否已经创建
    int is_running;            //是否在while循环中运行
} hotplug_context_t;

typedef struct
{
    int  addOrRemove;              //epoll 对应的fd
    char nodeName[80];			   //硬盘名字
    char partitionName[80];		   //分区名字
    int  findstep;
    long uptime;
} hotplug_diskinfo_t;



class HotplugMonitor
{
public:
    HotplugMonitor();
    int   create_uevent_socket();
    void  destroy_uevent_socket();
    void  hotplug_parse_line(int addOrRemove,const char *linebuf,hotplug_diskinfo_t &hotplug_Dskinfo);
    void  hotplug_parse_uevent(char* recv_buff,int recv_size,hotplug_diskinfo_t &hotplug_Dskinfo);
    static void* hotplug_thread_loop(void *arg);
    void  hotplugmonitor_run();
    int   start_hotplug_monitor();
    int   stop_hotplug_monitor();
    void  initPubZeroMq();
    void  destoryPubZeroMq();



public:
     //hotplug_context_t hotplug = {0};
    pthread_t hotplug_thread;  //对应的线程
    int epoll_fd;              //epoll 对应的fd
    int uevent_fd;             //热插拔节点的sock 句柄
    int is_start;              //线程是否已经创建
    int is_running;            //是否在while循环中运行
    char uevent_buff[KERNEL_UEVENT_LEN];
    ZeroMQ  *zmqVideoData;
};

#endif // HOTPLUGMONITOR_H

 

hotplugmonitor.cpp

#include "hotplugmonitor.h"
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/sysinfo.h>


static  long uptime(void)
{
    struct sysinfo info;
    sysinfo(&info);
    return info.uptime;
}

HotplugMonitor::HotplugMonitor()
{
  epoll_fd=0;              //epoll 对应的fd
  uevent_fd=0;             //热插拔节点的sock 句柄
  is_start=0;              //线程是否已经创建
  is_running=0;            //是否在while循环中运行
  bzero(uevent_buff,KERNEL_UEVENT_LEN);
}


 int HotplugMonitor::create_uevent_socket()
{
    int flags,retval;
    uevent_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
    if(uevent_fd<0)
    {
        printf("[hotplug] create_uevent_socket socket fail.\n");
        return -1;
    }
    flags = fcntl(uevent_fd, F_GETFL, 0);
    flags |= O_NONBLOCK;
    fcntl(uevent_fd, F_SETFL, flags);
    struct sockaddr_nl src_addr;
    memset(&src_addr, 0, sizeof(src_addr));
    src_addr.nl_family = AF_NETLINK;
    src_addr.nl_pid = getpid();
    src_addr.nl_groups = 0xffffffff;
    retval = bind(uevent_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
    if(retval < 0)
    {
        printf("[hotplug] create_uevent_socket bind fail.\n");
        close(uevent_fd);
        uevent_fd = 0;
        return -1;
    }
    return 0;
}

 void HotplugMonitor::destroy_uevent_socket()
{
     if(uevent_fd>0)
     {
         close(uevent_fd);
         uevent_fd = 0;
     }
}

 /***
addOrRemove:
      1 Add
      0 remove
  ***/

  void HotplugMonitor::hotplug_parse_line(int addOrRemove,const char *linebuf,hotplug_diskinfo_t &hotplug_Dskinfo){

     if(strstr(linebuf,"/block/sd")!=NULL){		//USB 硬盘
         const char *p_str=strstr(linebuf,"/block/sd");
         p_str=p_str+strlen("/block/sd");
         if((p_str+1)!=NULL&&*(p_str+1)=='/'){ //找分区所在行
             p_str=p_str+2;						//分区的名字
             hotplug_Dskinfo.addOrRemove=addOrRemove;
             strcpy(hotplug_Dskinfo.partitionName,p_str);
             memcpy(hotplug_Dskinfo.nodeName,p_str,strlen(p_str)-1);
             hotplug_Dskinfo.findstep+=PATIONNAMEFOUND;
             hotplug_Dskinfo.uptime=uptime();

         }else{
             p_str=p_str-2;
             hotplug_Dskinfo.addOrRemove=addOrRemove;
             memcpy(hotplug_Dskinfo.nodeName,p_str,strlen(p_str));
             hotplug_Dskinfo.findstep+=NODENAMEFOUND;
             hotplug_Dskinfo.uptime=uptime();
         }

     }else if(strstr(linebuf,"/block/mmcblk1")!=NULL){
         const char *p_str=strstr(linebuf,"/block/mmcblk1");
         p_str=p_str+strlen("/block/mmcblk1");
         if((p_str)!=NULL&&*(p_str)=='/'){	//找分区所在行
             p_str=p_str+1;
             hotplug_Dskinfo.addOrRemove=addOrRemove;
             strcpy(hotplug_Dskinfo.partitionName,p_str);
             memcpy(hotplug_Dskinfo.nodeName,p_str,strlen(p_str)-2);
             hotplug_Dskinfo.findstep+=PATIONNAMEFOUND;
             hotplug_Dskinfo.uptime=uptime();

         }else{
             p_str=p_str-strlen("mmcblk1");
             hotplug_Dskinfo.addOrRemove=addOrRemove;
             memcpy(hotplug_Dskinfo.nodeName,p_str,strlen(p_str));
             hotplug_Dskinfo.findstep+=NODENAMEFOUND;
             hotplug_Dskinfo.uptime=uptime();
         }
     }
 }


 void HotplugMonitor::hotplug_parse_uevent(char* recv_buff,int recv_size,hotplug_diskinfo_t &hotplug_Dskinfo)
{
     int i;
     if(recv_size>0)
        recv_buff[recv_size]='\0';
     else
        return ;
    stringstream input(recv_buff);
    string temp;
    //getline 参数:第一个流,第二个数据,第三个结束符(默认 \n)
    while (getline(input, temp, '\n')){
        const char *p_str=temp.c_str();
        if(strstr(p_str,"add@/devices")!=NULL)
            hotplug_parse_line(1,p_str,hotplug_Dskinfo);
        else if(strstr(p_str,"remove@/devices")!=NULL)
            hotplug_parse_line(0,p_str,hotplug_Dskinfo);
    }
}

 void* HotplugMonitor::hotplug_thread_loop(void *arg)
{
    HotplugMonitor *ptr=(HotplugMonitor *)arg;
    ptr->hotplugmonitor_run();
    return NULL;
}


  void HotplugMonitor::  hotplugmonitor_run(){
      hotplug_diskinfo_t hotplug_Dskinfo;
      memset(&hotplug_Dskinfo,0,sizeof(hotplug_diskinfo_t));
      int i,ret,recv_size;
      struct epoll_event events[EPOLL_EVENT_SIZE];
      LogUtils::myPrintf(LOG_INFO,"hotplugmonitor_run PID %d -----------Begin----\n",syscall(SYS_gettid));
      while(is_running)
      {
          ret = epoll_wait(epoll_fd,events,EPOLL_EVENT_SIZE,EPOLL_TIMEOUT);  //等待节点
          for(i=0;i<ret;i++)
          {
              // 判断是否是要监听的节点可读
              if((events[i].data.fd == uevent_fd) && (events[i].events&EPOLLIN))
              {
                 recv_size = recv(uevent_fd, uevent_buff, KERNEL_UEVENT_LEN, 0);
                 if(recv_size > KERNEL_UEVENT_LEN)
                 {
                     printf("[hotplug] receive overflow!\n");
                     continue;
                 }
                 hotplug_parse_uevent(uevent_buff,recv_size,hotplug_Dskinfo);
              }
          }
          if(hotplug_Dskinfo.findstep!=0&&hotplug_Dskinfo.uptime>0){
                      if((uptime()-hotplug_Dskinfo.uptime)>=1){
                          char sendbuf[BYTES_BUFFER_SIZE]={0};
                          if(hotplug_Dskinfo.findstep==NODENAMEFOUND)
                              strcpy(hotplug_Dskinfo.partitionName,hotplug_Dskinfo.nodeName);
                          LogUtils::myPrintf(LOG_INFO,"%s nodename:%s partionname:%s\n",hotplug_Dskinfo.addOrRemove?"add":"removed",\
                                      hotplug_Dskinfo.nodeName,hotplug_Dskinfo.partitionName);

                          sprintf(sendbuf,"HotplugEvent:%d,%s,%s",hotplug_Dskinfo.addOrRemove,hotplug_Dskinfo.nodeName,hotplug_Dskinfo.partitionName);
                          zmqVideoData->msgSendDirectly(sendbuf,strlen(sendbuf));

                          memset(&hotplug_Dskinfo,0,sizeof(hotplug_diskinfo_t));
                      }
          }
      }
      is_start = 0;
      destroy_uevent_socket();
      close(epoll_fd);
      LogUtils::myPrintf(LOG_INFO,"hotplugmonitor_run PID %d -----------End----\n",syscall(SYS_gettid));
      pthread_exit(0);
  }


int HotplugMonitor::start_hotplug_monitor()
{
    if(is_start)
    {
        printf("[hotplug] start_hotplug_monitor had start.\n");
        return 0;
    }
    is_start = 1;      //先标志线程已经创建

    if(create_uevent_socket())
    {
        printf("[hotplug_core] create_uevent_socket fail.\n");
        is_start = 0;
        return 0;
    }
    epoll_fd = epoll_create(EPOLL_FD_SIZE);
    struct epoll_event ev;
    ev.events = EPOLLIN;
    ev.data.fd = uevent_fd;
    epoll_ctl(epoll_fd,EPOLL_CTL_ADD,uevent_fd,&ev);  //监听fd
    is_running = 1;

    if(pthread_create(&(hotplug_thread), NULL, hotplug_thread_loop, this)){
        printf("[hotplug] pthread_create hotplug_thread_loop fail.\n");
        is_start = 0;  //线程创建失败
        return -1;
    }
    return 0;
}

int HotplugMonitor::stop_hotplug_monitor()
{
    if(is_start == 0) //如果线程还没有启动
    {
        printf("[hotplug] start_hotplug_monitor had not start.\n");
        return -1;
    }

    is_running = 0; //让线程结束
    pthread_join(hotplug_thread, NULL);   //等待线程运行结束
    return 0;
}

void HotplugMonitor::initPubZeroMq(){
    string control_gui=CONTROL_GUI;
    int port=IniParse::readIniInt(CONFIGINI,control_gui+"."+"hotplug_pub_port",9997);
    zmqVideoData = new ZeroMQ;
    if(zmqVideoData->InitZeroMq(ZMQ_PUB)!=0)
        return ;
    if(zmqVideoData->ZeroMqBind(port)!=0)
        return ;
}
void HotplugMonitor::destoryPubZeroMq(){

    if(zmqVideoData->pSock != NULL){
            zmq_close(zmqVideoData->pSock);
            zmqVideoData->pSock= NULL;
     }
     if(zmqVideoData->pCtx != NULL){
            zmq_ctx_destroy(zmqVideoData->pCtx);
            zmqVideoData->pCtx= NULL;
     }
}


 

初始化:

hotplugMonitor=new HotplugMonitor;
hotplugMonitor->initPubZeroMq();
hotplugMonitor->start_hotplug_monitor();

通过 zmqVideoData->msgSendDirectly(sendbuf,strlen(sendbuf)); 将热插拔信息的 zeroMQ PUB出去

可识别USB 类型,SD卡,SSD硬盘类型热插拔

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值