主要通过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硬盘类型热插拔