QEMU Machine ProtocolQMP协议规范实战指南从 JSON 消息格式到源码级实现解析【免费下载链接】qemuOfficial QEMU mirror. Please see https://www.qemu.org/contribute/ for how to submit changes to QEMU. Pull Requests are disabled. Please only use release tarballs from the QEMU website.项目地址: https://gitcode.com/gh_mirrors/qe/qemuQMPQEMU Machine Protocol是 QEMU 提供的基于 JSON 的机器级控制协议供上层应用如 libvirt、OpenStack 等管理工具以结构化方式驱动 QEMU 进程同时也被 QEMU Guest AgentQGA用于宿主机与客户机操作系统之间的交互。本文将基于仓库中的官方规范文档 docs/interop/qmp-spec.rst结合 QEMU 源码monitor 层、qapi 层与命令定义qapi/*.json系统讲解 QMP 的协议格式、能力协商、命令执行、响应结构、异步事件、OOB 带外执行、解析器复位、QGA 同步、兼容性约束与下游扩展规范帮助读者完整掌握 QMP 的协议细节并能够直接编写出符合规范的 QMP 客户端。QMP 协议总览QMP 是一个以换行符为边界、基于 JSON 文本行的请求/响应协议。它的定位是机器级machine-level接口与面向人机交互的 HMPHuman Monitor Protocol不同QMP 的所有消息都是结构化 JSON 对象便于程序化解析与自动化运维。根据 docs/interop/qmp-spec.rst该协议同时服务两类角色Server服务端QEMU 进程本身或 QEMU Guest AgentQGAClient客户端任何通过 QMP 与 Server 通信的应用程序。具体命令与数据结构的详细参考分别见 docs/interop/qemu-qmp-ref.rstQEMU QMP 参考与 qemu-ga-refQGA 参考本文聚焦协议本身的通用格式规范。协议的基本数据约定规范中提到的所有 JSON 数据结构均以如下形式表示json-DATA-STRUCTURE-NAME其中DATA-STRUCTURE-NAME是任意合法的 JSON 数据结构依据 JSON 标准 RFC 8259 定义。协议层的核心约定如下编码Server 期望输入为 UTF-8 编码输出为 ASCII 编码成员顺序文档中为了阅读方便会按固定顺序列出 json-object 的成员但真实协议中成员可以是任意顺序客户端不能假设任何特定顺序数组顺序json-array 的元素顺序默认是重要的除非另行说明客户端应保留数组顺序语义重复键在同一个 json-object 中重复出现同一个键会产生不可预测的结果属于未定义行为单引号扩展为方便起见Server 接受用单引号替代标准双引号的 json-string两种输入形式都额外理解转义序列\表示单引号。但 Server 在输出时只会使用双引号。消息的通用形态Server 发送的所有交互消息都是 json-object并且总是以 CRLF\r\n结尾。除非特别说明json-object 的所有成员都是必需的。连接建立Server Greeting服务端问候当客户端刚刚连接到 QMP 时Server 会立即发送一条问候消息greeting其作用有两点确认连接成功建立宣告 Server 已就绪可以进行能力协商见下文Capabilities Negotiation。问候消息格式{ QMP: { version: json-object, capabilities: json-array } }各成员含义versionServer 的版本信息格式与query-version命令的返回值一致包含qemu的三段式版本号major/minor/micro与package字段capabilities声明 Server 在基线规范之外支持的扩展能力数组内元素顺序无特定意义。从源码看问候消息由 monitor/qmp.c 中的qmp_greeting()生成它通过qmp_marshal_query_version()填充版本信息再遍历mon-capab_offered[]数组把 Server 支持的能力名如oob依次追加到cap_list中最终拼装为{QMP: {version: ..., capabilities: ...}}结构。也就是说greeting 中的 capabilities 列表是动态生成的只包含当前连接实际可用的能力。在 monitor/qmp.c 的monitor_qmp_caps_reset()中可以看到oob能力的提供与否取决于monitor_requires_iothread()的返回值——只有启用了 monitor I/O 线程如基于 iothread 的 chardev 后端时oob才会被列入 offered 能力。当前支持的能力目前规范定义的能力只有一个能力名说明oob支持带外Out-of-Band命令执行详见下文Out-of-band execution在 QAPI 定义层该能力对应的枚举类型QMPCapability定义于 qapi/control.json目前仅有oob一个取值。能力协商Capabilities Negotiation客户端建立连接后Server 处于Capabilities Negotiation能力协商模式。该模式有以下限制只允许执行qmp_capabilities命令其他任何命令都会返回CommandNotFound错误不投递任何异步事件消息。客户端应当通过qmp_capabilities命令显式开启 greeting 中已宣告且自身支持的能力。qmp_capabilities命令的行为在 qapi/control.json 中有完整定义其要点包括可选参数enable要启用的QMPCapability值列表客户端不得启用 greeting 中未提及的能力若省略该字段表示不启用任何能力since 2.12该命令仅在刚连接时有效必须在其他任何命令被接受之前发出一旦 monitor 开始接受其他命令再调用就会失败客户端需要显式开启能力否则所有 QMP 能力默认关闭。从源码实现看monitor/qmp-cmds-control.c 中的qmp_qmp_capabilities()先检查当前命令表若mon-commands已经是qmp_commands即协商已完成则返回COMMAND_NOT_FOUND错误Capabilities negotiation is already complete, command ignored否则调用qmp_caps_accept()校验所请求的能力是否在mon-capab_offered[]中若客户端请求了未提供的能力会返回形如Capability %s not available的错误见 monitor/qmp-cmds-control.c。协商成功后mon-commands被切换为qmp_commandsServer 进入Command 模式。进入 Command 模式后能力变更生效除qmp_capabilities外的所有命令均被允许执行异步事件开始正常投递。qmp_capabilities命令还带有allow-preconfig标记见 qapi/control.json意味着在 preconfig 阶段也可调用。另外monitor/qmp.c 的monitor_qmp_dispatch()中还做了一层兜底在协商模式下若收到非qmp_capabilities命令且返回了CommandNotFound会将其错误描述替换为更有指导意义的Expecting capabilities negotiation with qmp_capabilities。命令执行Issuing Commands命令执行请求有两种格式{ execute: json-string, arguments: json-object, id: json-value }或请求带外执行{ exec-oob: json-string, arguments: json-object, id: json-value }各成员含义execute/exec-oob标识要执行的命令名。exec-oob请求带外执行要求能力协商阶段已启用oobarguments命令所需的参数对象当命令不需要参数时可省略每个命令都文档化了它接受何种参数内容id事务标识可选。若提供则对应的响应消息中会原样带回该id便于请求与响应配对id可以是任意 JSON 值实践中推荐使用每次递增的 json-number。从源码看qapi/qmp-dispatch.c 中的qmp_dispatch_check_obj()负责对请求对象做结构性校验execute或启用了oob时的exec-oob必须是字符串arguments必须是对象id会被放行出现重复的execute/exec-oob键或未知键则报错。这印证了协议严格校验、宁严勿松的设计取向。Out-of-band 带外执行默认情况下Server顺序地读取、执行并响应命令客户端因此会按发出顺序收到响应。启用oob能力通过能力协商后行为发生变化Server 一边读取一边把命令排入队列再逐一从队列取出执行带外命令插队exec-oob命令会跳过队列中的在带命令被立即执行因此客户端可能先收到该命令的响应后收到先前在带命令的响应为把响应匹配回命令客户端必须为带外命令携带id规范建议接受oob能力的客户端为所有命令都携带id如果客户端发送在带命令的速度超过 Server 的执行速度Server 会暂停读取请求直到请求队列长度降到可接受范围为保证带外命令能被读取并执行客户端在途in-flight的在带命令最多不要超过 8 个只有少数命令支持带外执行判断标准是query-qmp-schema输出中该命令带有allow-oob: true。从源码看带外命令的插队路径在 monitor/qmp.c 的handle_qmp_command()中非常直观一旦检测到请求含exec-oob键qmp_is_oob(qdict)就立即调用monitor_qmp_dispatch()执行并返回根本不会进入在带命令的排队逻辑g_queue_push_tail(mon-qmp_requests, ...)。在带命令的队列上限由QMP_REQ_QUEUE_LEN_MAX控制见 monitor/qmp.c队列满时monitor_suspend()会挂起输入待 monitor/qmp.c 的monitor_qmp_dispatcher_co()协程消费后monitor_resume()恢复——这就是规范中暂停读取请求的底层实现。哪些命令支持 OOB查看 QAPI 定义即可例如迁移控制命令migrate-pause、migrate-continue定义在 qapi/migration.jsonyank 系列命令在 qapi/yank.json它们都显式标注了allow-oob: true。而allow-oob字段本身在 QAPI 内省结构中定义为布尔类型见 qapi/introspect.json。命令响应Commands Responses命令执行后 Server 会产生两类响应成功success或失败error。只要命令携带了id对应的响应消息中就会附带相同的id客户端应丢弃所有id未知的响应。成功响应格式{ return: json-value, id: json-value }return命令返回的数据具体内容按命令而定——通常是 json-object 或 json-array有时是 json-number、json-string若命令无返回数据则为空 json-object{}id若客户端发出时携带了事务标识则原样返回。错误响应格式{ error: { class: json-string, desc: json-string }, id: json-value }class错误类别名称例如GenericErrordesc人类可读的错误描述。客户端不应尝试解析该文本它不构成稳定接口id若客户端发出时携带了事务标识则原样返回。需要注意某些错误可能发生在 Server 尚未读取到id成员之前例如 JSON 解析失败此时即使客户端提供了id错误响应中也不包含id。带外执行中的响应乱序在启用oob后响应的到达顺序不再保证与请求发出顺序一致原因见上文因此客户端绝不能假设响应顺序必须以id为唯一的配对依据。异步事件Asynchronous Events由于状态变化Server 可能在任何时候只要不处于响应发送中间主动向客户端推送消息这类消息称为异步事件。格式{ event: json-string, data: json-object, timestamp: { seconds: json-number, microseconds: json-number } }各成员含义event事件名称data事件专属数据按事件定义可选timestamp事件在 Server 侧发生的精确时间是固定结构的 json-objectseconds和microseconds表示相对 Unix Epoch1970-01-01的时间若获取宿主机时间失败两个成员都会被置为-1。事件的具体清单见 docs/interop/qemu-qmp-ref.rst如POWERDOWN、RESET、SHUTDOWN、DEVICE_DELETED等。此外规范还说明部分事件被限速为每秒至多一条若一秒钟内到达多条相似事件除最后一条外其余全部丢弃且最后一条会被延迟投递相似通常指事件类型相同。该机制用于防止事件洪泛压垮客户端。值得注意的是在能力协商模式下异步事件不会被投递见上文Capabilities Negotiation源码对应实现是 monitor/qmp.c 的monitor_qmp_emit_event()若qmp-commands qmp_cap_negotiation_commands则直接返回不发送任何事件。将 JSON 解析器恢复到已知良好状态不完整或非法的输入可能让 Server 的 JSON 解析器陷入无法继续解析后续命令的状态。恢复方法是人为制造一个词法错误lexical error最干净的做法是发送一个 ASCII 控制字符——但不能是\t水平制表符、\r回车、\n换行。如果客户端需要兼容老版本 QEMU它们可能无法把普通控制字符标记为错误则应改发一个0xFF 字节。QGA 同步QGA Synchronization当客户端通过不具备完善连接语义的传输通道如 virtio-serial连接 QGA 时QGA 可能已经读取了上一个客户端遗留的部分输入。此时客户端需要使用上一节解析器恢复到已知良好状态的方法强制 QGA 的解析器进入已知良好状态客户端还可能收到上一个客户端未读走的输出。为跳过这些残留输出QGA 提供了guest-sync-delimited命令详见 QGA 参考文档 qemu-ga-ref。QMP 实战示例规范给出了完整的真实交互示例其中-表示客户端发送-表示 Server 回复。示例 1Server greeting- { QMP: {version: {qemu: {micro: 0, minor: 0, major: 3}, package: v3.0.0}, capabilities: [oob] } }示例 2能力协商- { execute: qmp_capabilities, arguments: { enable: [oob] } } - { return: {}}示例 3简单执行stop命令- { execute: stop } - { return: {} }示例 4查询 KVM 信息带 id- { execute: query-kvm, id: example } - { return: { enabled: true, present: true }, id: example}示例 5解析错误- { execute: } - { error: { class: GenericError, desc: JSON parse error, expecting value } }示例 6Powerdown 事件- { timestamp: { seconds: 1258551470, microseconds: 802384 }, event: POWERDOWN }示例 7带外执行错误场景- { exec-oob: migrate-pause, id: 42 } - { id: 42, error: { class: GenericError, desc: migrate-pause is currently only supported during postcopy-active state } }可以看到解析错误示例 5由于发生在读取id之前错误响应中没有id而带外命令示例 7是合法 JSONid被原样带回。这正对应前文关于错误响应中id是否存在的说明。兼容性考虑Compatibility Considerations协议在演进过程中保持严格的向后兼容策略不兼容的协议改动默认关闭并通过 greeting 中的 capabilities 数组宣告客户端检查该数组后只启用自己支持的能力QMP Server 对命令参数执行类型检查若某个值与其键的期望类型不符或客户端包含 Server 无法识别的键会生成错误这种严格性可以及早暴露客户端对 Server schema 的错误假设。客户端可以假定这类校验错误发生在命令产生任何副作用之前即校验失败不会留下半执行状态。但客户端不得假设以下任何一点json-array 的长度json-object 的大小——特别是未来版本可能新增键客户端应能忽略未知键json-object 成员或 json-array 元素的顺序命令可能产生的错误数量——新版本 Server 可能给任何既有命令增加新错误。此外任何以x-开头的命令或成员名都被视为实验性的未来版本可能以不兼容方式被移除或修改。最后Server 只保证输出合法 JSON除此之外客户端应遵循发送时保守接收时宽容conservative in what they send, and liberal in what they accept的原则。下游扩展 QMPDownstream Extension of QMP官方建议下游消费者downstream不要修改 QMP以便管理工具无需特殊逻辑即可同时支持上游与下游版本。但既然现实中有不可避免的修改需求规范给出了明确的互操作约定保留命名空间__前缀QMP 为下游保留了以__双下划线开头的 JSON 对象成员名downstream names。上游永远不会用这些名字命名命令、参数、错误或异步事件。下游新增的任何名字都必须以__开头为保证与其他下游的兼容性强烈建议再追加__RFQDN_前缀RFQDN 是你拥有且合法的反向完全限定域名。例如 qemu-kvm 专属的 monitor 命令(qemu) __org.linux-kvm_enable_irqchip下游行为约束除提供额外能力外不得改动 server greeting但规范也指出连新增能力都不被鼓励见下上一节兼容性考虑对下游同样适用对于不含下游成员的输入下游必须表现得与上游完全一致唯一的例外是它可以在输出中添加带下游名字的成员因此只要客户端不发送含下游成员的输入、并能正确忽略收到的下游成员就不应该能区分出上游与下游。关于下游修改的官方建议新增命令是允许的若想扩展现有命令考虑用带新行为的新命令替代新增异步消息是允许的若想扩展现有消息考虑新增一条消息而非修改为新命令引入新错误是允许的但给现有命令添加新错误属于扩展行为应按第 1 条处理即改用新命令新增能力被强烈劝阻能力用于演进基础协议本身多个分叉的基础协议方言是最不受欢迎的结局。从源码理解 QMP 的完整生命周期综合以上规范与源码一个典型 QMP 会话的完整流程可以总结为连接客户端建立 TCP如-qmp tcp:localhost:4444,serveron,waitoff或 unix socket 连接GreetingServer 在CHR_EVENT_OPENED时见 monitor/qmp.c把命令表切到qmp_cap_negotiation_commands、复位能力并发送 greeting能力协商客户端发送qmp_capabilities可带enable: [oob]成功后进入 Command 模式monitor/qmp-cmds-control.c命令执行客户端发送{ execute: ... }请求经 JSON 解析json_message_parser_feed见 monitor/qmp.c、结构性校验qapi/qmp-dispatch.c、分发执行后通过qmp_send_response()返回结果monitor/qmp.c异步事件状态变化触发monitor_qmp_emit_event()主动推送仅在 Command 模式断开CHR_EVENT_CLOSED时清理请求队列、重建解析器monitor/qmp.c。对于想要进一步深入源码的读者以下文件是核心入口协议规范 docs/interop/qmp-spec.rst命令与内省参考 docs/interop/qemu-qmp-ref.rstQMP 主实现 monitor/qmp.c控制类命令实现 monitor/qmp-cmds-control.c分发与校验核心 qapi/qmp-dispatch.c控制类命令与能力枚举的 QAPI 定义 qapi/control.jsonOOB 相关命令定义allow-oob: true qapi/migration.json、qapi/yank.json内省结构中allow-oob字段 qapi/introspect.json掌握以上协议格式与源码路径后开发者既可以直接手工编写 QMP 客户端脚本如用 Python 的socket连接并收发 JSON也可以在此基础上理解 libvirt、OpenStack 等上层管理栈如何通过 QMP 驱动 QEMU为诊断问题、定制管理工具或做下游集成打下坚实基础。【免费下载链接】qemuOfficial QEMU mirror. Please see https://www.qemu.org/contribute/ for how to submit changes to QEMU. Pull Requests are disabled. Please only use release tarballs from the QEMU website.项目地址: https://gitcode.com/gh_mirrors/qe/qemu创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
ZCode agent-browser 会话管理完全指南:多会话隔离、状态持久化与并发浏览实战 ZCode agent-browser 会话管理完全指南:多会话隔离、状态持久化与并发浏览实战 【免费下载链接】ZCode Z.ais coding agent harness. Powerful, intelligent, extensible. 项目地址: https://gitcode.com/gh_mirrors/zco/ZCode
本篇指南聚焦 ZCode 仓库内置的… · 2026/9/23 1:15:14
PolarDB从节点异常排查复盘:从复制延迟到慢查询的根因与恢复 大年初七开工第一天,我人还没从节后综合征里缓过来,手机就连续震了七八下,直接被拉进了一个“PolarDB从节点异常”的应急群。群里消息一条比一条急:“报表查不出来了”“只读地址连不上”“从节点是不是挂了”。那一刻脑子是懵的&… · 2026/9/23 3:40:52
5个步骤搞懂字幕模板源码解析,告别教程依赖症 5个步骤搞懂字幕模板源码解析,告别教程依赖症 看了一堆视频,跟着敲完代码,一动手写项目就卡壳?这不是你的问题,是大多数教程的毛病。他们只教“怎么做”,不教“为什么这么做”,导致你脑子里全是碎片,没有底层逻辑。今天咱们不谈虚的,直接拆解【字幕… · 2026/9/23 3:40:52
Java多线程两两交换数据:Exchanger原理、用法与实战选型全解析 很多用 Java 做并发编程的同学,对CountDownLatch、CyclicBarrier、Semaphore这些工具如数家珍,但一问到Exchanger,十有八九会愣一下。这也不怪大家,毕竟在实际项目里它出现的频率确实不高。但你要是真把它研究透了,会发… · 2026/9/23 3:40:52
提示词不是门槛,检验卡才是:一套可复用的AI提示词验收方法 说句得罪人的话:现在满屏都在教“怎么写提示词”,但真正拉开差距的,不是那个能生成漂亮结果的提示词,而是你拿什么标准来判断这个结果是不是真的合格。提示词谁都会写,检验卡才是门槛——这句话我越做越觉得是真理。尤… · 2026/9/23 3:40:52
GTA6主机联机卡顿?PS5/Xbox网络优化实战指南 GTA6的预购和发售信息一刷出来,PS5和Xbox玩家群里的画风就变了:今天有人问“线上模式进了半天进不去”,明天就有人吐槽“下载更新动不动断连”。主机玩家以前对网络问题没那么敏感,毕竟单机游戏离线也能玩,可GTA6这种体… · 2026/9/23 3:40:45
NVIDIA显卡驱动更新全指南:从DDU卸载到nvidia-smi报错排查 先别急着下载最新驱动。很多人一看到 NVIDIA 官网出了新版本,习惯性就直接点下载,结果装完不是黑屏就是性能反而下降,更头疼的是驱动装到一半报错、装完才发现控制面板没了、或者直接干脆连显卡都识别不到。这种事情我在群里被问过少说上百遍… · 2026/9/23 3:40:45
3招搞定手机怎么下载微信面试难题实战项目解析 3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29