libvirt的event监听机制和代码实现

这篇具有很好参考价值的文章主要介绍了libvirt的event监听机制和代码实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


1.简介

libvirt是目前使用最为广泛的对KVM虚拟机继续管理的工具和应用程序接口,而且一些常用的虚拟机管理工具(如virsh、virt-manager等)和云计算框架平台(如:OpenStack、ZStack等)都在底层使用libvirt的应用程序接口。
libvirt是为了更方便地管理平台虚拟化技术而设计的开放源代码的应用程序接口(libvirt API)、守护进程(libvirtd)和管理工具(virsh),它不仅提供了对虚拟化客户机的管理,也提供了对虚拟化网络和存储的管理。
libvirt支持事件机制,在使用该机制注册之后,可以在发生特定的事件(如:domain的启动、暂停、恢复和停止等)时得到自己定义的一些通知。该功能由以virStream开头的一系列函数实现。


2.通过virsh演示event监听

第一步:使用命令event --help,查看event命令后面需要接哪些选项。
vireventrundefaultimpl,服务器,云计算,c语言,运维
第二步:使用命令event --all --loop --timestamp,监听hypervisor上所有domain的所有类型事件,并且循环监听,直到手动中断。
vireventrundefaultimpl,服务器,云计算,c语言,运维
第三步:另外打开一个窗口,destroy,或者start虚拟机。
vireventrundefaultimpl,服务器,云计算,c语言,运维
第四步:查看监听界面,会收到事件。
vireventrundefaultimpl,服务器,云计算,c语言,运维

3.通过libvirt API实现event监听的流程图

vireventrundefaultimpl,服务器,云计算,c语言,运维
vireventrundefaultimpl,服务器,云计算,c语言,运维
vireventrundefaultimpl,服务器,云计算,c语言,运维

4. virEvent API简介

4.1 virEventRegisterDefaultImpl

语法
int virEventRegisterDefaultImpl (void)
描述
注册基于poll()系统调用的默认事件实现。这是一个通用实现,任何客户机应用程序都可以使用它,不需要与外部事件循环impl集成。
为了进行正确的事件处理,一定要在打开到Hypervisor的连接之前实现事件注册。
注册之后,应用程序必须在循环中调用 virEventRunDefaultImpl ()来处理事件。如果不这样做,可能会导致连接由于keepalive超时而被意外关闭。默认事件循环完全支持处理和超时事件,但只在libvirt API调用(如virEventAddHandle()或virConnectDomainEventRegisterAny())注册的事件上唤醒。
返回值
0,表示成功。1,表示失败。

4.2. virEventHandleType

handle事件的类型。
enum virEventHandleType {
VIR_EVENT_HANDLE_READABLE = 1 (0x1; 1 << 0) // 可读
VIR_EVENT_HANDLE_WRITABLE = 2 (0x2; 1 << 1) // 可写
VIR_EVENT_HANDLE_ERROR = 4 (0x4; 1 << 2) // 异常
VIR_EVENT_HANDLE_HANGUP = 8 (0x8; 1 << 3) // 挂起
}

4.3. virEventAddHandle

语法
int virEventAddHandle (int fd, int events, virEventHandleCallback cb, void * opaque, virFreeCallback ff)
描述
为监视文件句柄事件注册一个回调。这个函数要求一个事件循环之前已经用virEventRegisterImpl()或virEventRegisterDefaultImpl()注册过。
fd必须总是总是一个C运行时文件描述符。在Windows上,如果调用者只有一个HANDLE,可以使用_open_osfhandle()方法打开一个关联的C运行时文件描述符,用于此API。打开一个运行时文件描述符后,CloseHandle()一定不能使用,相反,close()将关闭运行时文件描述符及其原始关联的HANDLE。
参数
fd:监控事件的文件句柄;
events:virEventHandleType常量中要监视的事件的bitset;
cb:当事件发生时调用的回调函数;
opaque:要传递给回调的用户数据;
ff:当句柄被移除时,回调到释放不透明;
返回值
如果文件句柄不能注册,则返回-1。否则,将使用句柄监视号来更新和注销事件。
提示
使用linux的系统调用函数pipe(),获取fd;
events为用户传入的事件类型,例如VIR_DOMAIN_EVENT_ID_LIFECYCLE;
opaque相当于main中的argc和argv,用于接收用户的数据,具体使用看业务逻辑;即,可以用于传数据,也可以传NULL;
ff可以为NULL;

4.4. virEventAddTimeout

语法
int virEventAddTimeout (int timeout, virEventTimeoutCallback cb, void * opaque, virFreeCallback ff)
描述
为计时器事件注册一个回调。这个函数要求一个事件循环之前已经用virEventRegisterImpl()或virEventRegisterDefaultImpl ()注册过。
将timeout设置为-1将禁用计时器。将timeout设置为零将导致它在每次事件循环迭代时触发。
参数:
timeout:事件之间的时间间隔,以毫秒为单位
cb:当事件发生时调用的回调函数virEventTimeoutCallback
opaque:要传递给回调的用户数据;(相当于main中的argc和argv,用于接收用户的数据,具体使用看业务逻辑)
ff:释放不透明数据团的回调函数
返回值
如果定时器不能注册,返回-1。否则,注册成功时为正整数定时器id。

5. virConnectDomainEvent API简介

5.1. virConnectDomainEventRegisterAny

语法
int virConnectDomainEventRegisterAny (
virConnectPtr conn,
virDomainPtr dom,
int eventID,
virConnectDomainEventGenericCallback cb,
void * opaque,
virFreeCallback freecb)

描述
添加一个回调来接收域上发生的任意域事件的通知。这个函数要求一个事件循环之前已经用virEventRegisterImpl()或virEventRegisterDefaultImpl ()注册过。
如果dom是非null,则只监视特定的域。如果dom为NULL,则将监视任何域的事件。
大多数类型的事件都有一个回调函数,为事件提供一组自定义参数。因此,在注册事件时,需要使用VIR_DOMAIN_EVENT_CALLBACK()宏强制转换提供的函数指针,以匹配此方法的签名。
在传递事件时传递给回调函数的virDomainPtr对象句柄只在回调函数执行期间有效。如果回调函数希望在回调函数返回后保留域对象,它应该通过调用virDomainRef()获取对域对象的引用。一旦对象不再需要,就可以通过调用virDomainFree()释放引用。
这个方法的返回值是回调的一个非负整数标识符。要取消注册回调,应该将此回调ID传递给virConnectDomainEventDeregisterAny()方法。

参数
conn:pointer to the connection;
dom:所指向的domain;
eventID:所接收的事件类型;
cb:回调到处理域事件的函数;
opaque:传递给回调的不透明数据;
freecb:可选函数,当不再使用时释放不透明;

返回值
成功时使用回调标识符,失败时使用-1。

5.2. virConnectDomainEventDeregisterAny

语法
int virConnectDomainEventDeregisterAny (virConnectPtr conn, int callbackID)

描述
移除一个事件回调。
callbackID参数应该是从前面的virConnectDomainEventRegisterAny()方法获得的值。

2.3 参数
conn:pointer to the connection;
callbackID:回调标识;(通过virConnectDomainEventRegisterAny()方法获得)

返回值
0 on success, -1 on failure. 某些管理程序的旧版本有时会在成功时返回一个正数,但是没有任何关于该数字表示什么的可靠语义。

5.3. virConnectDomainEventRegister

语法
int virConnectDomainEventRegister (
virConnectPtr conn,
virConnectDomainEventCallback cb,
void * opaque,
virFreeCallback freecb)

描述
添加一个回调来接收在连接上发生的域生命周期事件的通知。这个函数要求一个事件循环之前已经用virEventRegisterImpl()或virEventRegisterDefaultImpl ()注册过。

不再推荐使用此方法。相反,应用程序应该尝试virConnectDomainEventRegisterAny(),它具有更灵活的API契约。

在传递事件时传递给回调函数的virDomainPtr对象句柄只在回调函数执行期间有效。如果回调函数希望在回调函数返回后保留域对象,它应该通过调用virDomainRef来获取对域对象的引用。一旦对象不再需要,就可以通过调用virDomainFree来释放引用。

参数
conn:pointer to the connection;
cb:回调到处理域事件的函数;
opaque:传递给回调的不透明数据
freecb:可选函数,当不再使用时释放不透明

返回值
0代表成功,-1代表失败。某些管理程序的旧版本有时会在成功时返回一个正数,但是没有任何关于该数字表示什么的可靠语义。

5.4. virConnectDomainEventDeregister

语法
int virConnectDomainEventDeregister (virConnectPtr conn, virConnectDomainEventCallback cb)
描述
删除以前使用virConnectDomainEventRegister()函数注册的回调。
不再推荐使用此方法。相反,应用程序应该尝试virConnectDomainEventDeregisterAny(),它具有更灵活的API契约。
参数
conn:pointer to the connection
cb:回调到处理域事件的函数;
返回值
0 on success, -1 on failure. 某些管理程序的旧版本有时会在成功时返回一个正数,但是没有任何关于该数字表示什么的可靠语义。

5.5. virDomainEventID

在eventRegister中需要输入eventid。
enum virDomainEventID {
VIR_DOMAIN_EVENT_ID_LIFECYCLE = 0,
VIR_DOMAIN_EVENT_ID_REBOOT = 1,
….
}
5.6. virDomainEventType
enum virDomainEventType {
VIR_DOMAIN_EVENT_DEFINED = 0 (0x0)
VIR_DOMAIN_EVENT_UNDEFINED = 1 (0x1)
VIR_DOMAIN_EVENT_STARTED = 2 (0x2)
VIR_DOMAIN_EVENT_SUSPENDED = 3 (0x3)
VIR_DOMAIN_EVENT_RESUMED = 4 (0x4)
VIR_DOMAIN_EVENT_STOPPED = 5 (0x5)
VIR_DOMAIN_EVENT_SHUTDOWN = 6 (0x6)
VIR_DOMAIN_EVENT_PMSUSPENDED = 7 (0x7)
VIR_DOMAIN_EVENT_CRASHED = 8 (0x8)
VIR_DOMAIN_EVENT_LAST = 9 (0x9)
}
上述type均属于EventID中的VIR_DOMAIN_EVENT_ID_LIFECYCLE。

6. 实现代码

#include <stdio.h>
#include <stdlib.h>
#include <libvirt/libvirt.h>
#include <pthread.h>
#include <time.h>
static int myEventCallback(virConnectPtr conn,
virDomainPtr dom,
int event,
int detail,
void *opaque) 
{
const char *name = virDomainGetName(dom);
struct tm *currTime;
time_t now;
time(&now);
currTime = localtime(&now);

switch(event) {
case VIR_DOMAIN_EVENT_STARTED:
printf("%d/%d/%d %d:%d:%d An STARTED event(%d) occurred in the domain = < %s >.\n", currTime->tm_year + 1900, currTime->tm_mon + 1, currTime->tm_mday, currTime->tm_hour, currTime->tm_min, currTime->tm_sec, event, name);
break;
case VIR_DOMAIN_EVENT_STOPPED:
printf("%d/%d/%d %d:%d:%d An STOPPED event(%d) occurred in the domain = < %s >.\n", currTime->tm_year + 1900, currTime->tm_mon + 1, currTime->tm_mday, currTime->tm_hour, currTime->tm_min, currTime->tm_sec, event, name);
break;
case VIR_DOMAIN_EVENT_DEFINED:
printf("%d/%d/%d %d:%d:%d An DEFINED event(%d) occurred in the domain = < %s >.\n", currTime->tm_year + 1900, currTime->tm_mon + 1, currTime->tm_mday, currTime->tm_hour, currTime->tm_min, currTime->tm_sec, event, name);
break;
case VIR_DOMAIN_EVENT_UNDEFINED:
printf("%d/%d/%d %d:%d:%d An UNDEFINED event(%d) occurred in the domain = < %s >.\n", currTime->tm_year + 1900, currTime->tm_mon + 1, currTime->tm_mday, currTime->tm_hour, currTime->tm_min, currTime->tm_sec, event, name);
break;
case VIR_DOMAIN_EVENT_SUSPENDED:
printf("%d/%d/%d %d:%d:%d An SUSPENDED event(%d) occurred in the domain = < %s >.\n", currTime->tm_year + 1900, currTime->tm_mon + 1, currTime->tm_mday, currTime->tm_hour, currTime->tm_min, currTime->tm_sec, event, name);
break;
case VIR_DOMAIN_EVENT_RESUMED:
printf("%d/%d/%d %d:%d:%d An RESUMED event(%d) occurred in the domain = < %s >.\n", currTime->tm_year + 1900, currTime->tm_mon + 1, currTime->tm_mday, currTime->tm_hour, currTime->tm_min, currTime->tm_sec, event, name);
break;
case VIR_DOMAIN_EVENT_SHUTDOWN:
printf("%d/%d/%d %d:%d:%d An SHUTDOWN event(%d) occurred in the domain = < %s >.\n", currTime->tm_year + 1900, currTime->tm_mon + 1, currTime->tm_mday, currTime->tm_hour, currTime->tm_min, currTime->tm_sec, event, name);
break;
case VIR_DOMAIN_EVENT_PMSUSPENDED:
printf("%d/%d/%d %d:%d:%d An PMSUSPENDED event(%d) occurred in the domain = < %s >.\n", currTime->tm_year + 1900, currTime->tm_mon + 1, currTime->tm_mday, currTime->tm_hour, currTime->tm_min, currTime->tm_sec, event, name);
break;
case VIR_DOMAIN_EVENT_CRASHED:
printf("%d/%d/%d %d:%d:%d An CRASHED event(%d) occurred in the domain = < %s >.\n", currTime->tm_year + 1900, currTime->tm_mon + 1, currTime->tm_mday, currTime->tm_hour, currTime->tm_min, currTime->tm_sec, event, name);
break;
default:
printf("%d/%d/%d %d:%d:%d An UNKOWN event(%d) occurred in the domain = < %s >.\n", currTime->tm_year + 1900, currTime->tm_mon + 1, currTime->tm_mday, currTime->tm_hour, currTime->tm_min, currTime->tm_sec, event, name);
break;
}
return 0;
}
static void* eventThreadLoop() {
while(1) {
if(virEventRunDefaultImpl() < 0) {
printf("Run errer.\n");
}
}
abort();
}
int main() {
virConnectPtr conn = NULL;
int eventid = VIR_DOMAIN_EVENT_ID_LIFECYCLE;
virEventRegisterDefaultImpl();
conn = virConnectOpen(NULL);
pthread_t eventThread;
pthread_create(&eventThread, NULL, eventThreadLoop, NULL);
int id = virConnectDomainEventRegisterAny(conn, 
NULL,
eventid,
VIR_DOMAIN_EVENT_CALLBACK(myEventCallback),
NULL,
NULL);
while(1) pause();
virConnectDomainEventDeregisterAny(conn, id);
virConnectClose(conn);
return 0;
}

7. 实验现象

对虚拟机进行操作:
vireventrundefaultimpl,服务器,云计算,c语言,运维
接收到的事件:
vireventrundefaultimpl,服务器,云计算,c语言,运维

8. 参考文献

[1] https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainEventType文章来源地址https://www.toymoban.com/news/detail-584012.html

到了这里,关于libvirt的event监听机制和代码实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • vue3中监听,组件通信如父子传值、Vuex、Event Bus的使用

    目录 一、监听 二、父子传值: 1、父传子: 2、子传父 三、全局状态管理(Vuex): 四、事件总线(Event Bus): 我们有一个父组件ParentComponent和一个子组件ChildComponent。在父组件中,我们使用:childProp=\\\"parentData\\\"将数据传递给子组件。在子组件中,我们使用defineProps来接收父组件

    2024年02月13日
    浏览(37)
  • 【web3j】java通过web3j监听并解析合约中的事件(event/emit)

    ① 查询链上数据用的rpc(本示例是binance的,测试网可以使用:https://data-seed-prebsc-2-s2.binance.org:8545) ② 自己还要有一个测试链上部署好的合约,合约中要有一个方法emit了事件。 ③ java依赖 一、 通过自己合约的abi和bin生成一个java文件,abi和bin可以在remix的compiler模块中获取,

    2024年02月09日
    浏览(47)
  • web3j的基础用法-6合约的监听器事件Event和过滤器EthFilter,以及NullPointed,调用失败导致的bug解决

    本篇以Uniswap为例(https://uniswap.org/) 合约地址 :0x1f9840a85d5af5bf1d1762f925bdaddc4201f984 (Uni) 监听合约Tranfer事件 调用代码 核心代码实现在这里 之前实验全量区块,导致请求多次失败,是由于个人RPC节点的请求和数据有限,为了测试出结果,从13763721L block到当前,结果毫秒级返

    2024年02月11日
    浏览(47)
  • 【Android学习笔记】事件监听机制详解

    两种事件处理机制 基于监听的事件处理 基于回调的事件处理 涉及到的三类对象 Event Source事件源,指各个组件。 Event 界面组件上发生的特定的事情,。 Event Listener监听事件源发生的事情。并对各种事情作出相应的响应。 Event Handler事件处理器,当事件监听器捕获事件后,由响

    2024年02月11日
    浏览(56)
  • Spring事件监听机制使用和原理解析

    你好,我是刘牌! 好久没有更新Spring了,今天来分享一下Spring的事件监听机制,之前分享过一篇Spring监听机制的使用,今天从原理上进行解析,Spring的监听机制基于观察者模式,就是就是我们所说的发布订阅模式,这种模式可以在一定程度上实现代码的解耦,如果想要实现系

    2024年02月08日
    浏览(40)
  • Java键盘事件处理及监听机制解析

    Java事件处理采用了委派事件模型。在这个模型中,当事件发生时,产生事件的对象将事件信息传递给事件的监听者进行处理。在Java中,事件源是产生事件的对象,比如窗口、按钮等;事件是承载事件源状态改变时的对象,比如键盘事件、鼠标事件、窗口事件等等。当事件发

    2024年02月13日
    浏览(37)
  • Java中的键盘监听机制(含实例)

    上文讲述了Java中的鼠标监听机制,本文将讲述监听事件中的最后一类:键盘监听,并且会实现一个建议的键盘监听的例子 与前面一样,这里就不多加赘述,直接上代码,注意我们要给整个界面绑定键盘监听,所以 不要把setBounds这行代码留着 这里我们使用 addKeyListener() 来实现

    2024年02月07日
    浏览(33)
  • 注意力机制(代码实现案例)

    学习目标 了解什么是注意力计算规则以及常见的计算规则. 了解什么是注意力机制及其作用. 掌握注意力机制的实现步骤. 1.1 注意力概念 我们观察事物时,之所以能够快速判断一种事物(当然允许判断是错误的), 是因为我们大脑能够很快把注意力放在事物最具有辨识度的部分从

    2024年03月09日
    浏览(31)
  • 45. Fabric2.2 事件监听机制应用

    本节全面讲述Fabric事件监听机制,并用实际客户端代码演示事件监听的特点、特性。 1. Fabric 2.2 支持的事件类型 RegisterBlockEvent : 区块事件监听,当产生区块时客户端收到消息,接收到完整的区块数据。 RegisterFilteredBlockEvent :也是区块事件监听,但完整的区块数据结构复杂,

    2023年04月26日
    浏览(36)
  • 面试题:如何知道java对象被垃圾回收掉,用代码实现一个能监听对象被回收的功能

    Java中无法直接判断一个对象是否被垃圾回收掉,因为Java的垃圾回收机制是自动的,程序员并不需要手动清理对象。但是,如果我们想要知道一个对象何时被回收掉,可以使用 finalize() 方法。 每个Java对象都有一个 finalize() 方法,这个方法会在对象被垃圾回收前调用一次。我们

    2024年02月02日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包