当前位置: 首页 > news >正文

ZMTP协议

ZoreMQ Transport Protocol是一个传输层协议,用于ZMQ的连接的信息交互,本文档描述的是3.0协议,主要分析基于NULL Security Mechanism


协议语法

ZMTP由三部分组成,分别是 greeting、handshake、traffic

部分描述构成
greeting描述ZMQ版本、安全机制等signature + version + mechanism + as-server + filler
handshake描述端类型,如 PUB/SUB,REQ/REP一个或多个command
traffic命令或者消息command

ZMTP Wireshark 抓包

WireShark 默认不提供ZMTP解析插件,需要自己配置,步骤如下:

插件仓库:https://github.com/whitequark/zmtp-wireshark

下载插件:https://github.com/whitequark/zmtp-wireshark/blob/master/zmtp-dissector.lua

将插件zmtp-dissector.lua放到WireShark安装目录,比如我的是:C:\Program Files\Wireshark

修改C:\Program Files\Wireshark\init.lua,在文件末尾添加

dofile(DATA_DIR.."zmtp-dissector.lua")

对基于TCP端口通讯ZMQ进行抓包,例如端口为7380,将该端口Decode As ZMTP

8607ab1ed5f523a6bbc4491ec74b924f.png
解析接如下

1b1998d082deac0fe4c96b7aafb00f94.png

greeting

greeting 固定64个字节大小,下面将依次介绍每个部分。

signature

固定10字节大小,固定值为ff 00 00 00 00 00 00 00 01 7f;

signature可以用来校验链接是否为ZMQ链接,连续读取10个字节,判断开头是否为0xff,结尾是否为0x7f

version

固定2字节大小,格式为{major_version, minor_version}3.0 协议则为03 00,实际编码过程中只会校验major_version;

mechanism

固定20字节大小,这里只介绍NULL Security Mechanism,也就是不校验,其值为NULL,剩余以内容填充0;

as-server

固定一个字节大小,0x00 或者 0x01 ,当mechanism为NULL时候,as-server必须为0

filler

填充greeting至64个字节。

抓包示意

由Wireshark解析过后的协议。

6bd633daef76a532eb2eed806a8e6485.png

Frame

greeting之后的所有数据格式都为Frame,包含commandmessage

frame的格式如下:

Frame = Flag + Payload Length + Payload

抓包示意如下
在这里插入图片描述

  • Flag
    Flag 为1字节大小,每位代表不同的意思,参考抓包解释
    在这里插入图片描述
    低1位:表示是否有更多Frame,这里用于ZMQ中sendmore属性
    低2位:表示长度是否为8字节长度,否则为1字节长度
    低3位:表示当前frame是否为Command
    其他:保留,为0

  • Payload Length
    数据长度,可以为1字节或者8字节大小,根据Flag中的标志位决定

  • Payload
    实际的数据,大小为Payload Length

handshake

此阶段用来交换对端的READY命令以及metadata,主要包含对端的类型。handshake本质是Command,为Frame的一种。
NULL Security Mechanism机制中,以PUB/SUB模式为例,handshake的数据如下:
在这里插入图片描述
Payload内容如下:

[1 byte] Command size + [n bytes]Command Name + [1 bytes]Metadata Key size + [n bytes]Metadata Key + [4 bytes]Metadata Value size + [n bytes]Metadata Value

使用Socket实现ZMQ SUB方法

代码如下:

//
//  ZMTP 3.0 debugging subscriber
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <WinSock2.h>
#include <ws2tcpip.h>#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
#include <cstdint>
#include <iostream>#pragma comment(lib, "ws2_32.lib")typedef struct
{uint8_t flags;     //  Must be zerouint8_t size;      //  Size, 0 to 255 byteuint8_t data[255]; //  Message data
} zmtp_msg_t;static void derp(char *s)
{perror(s);exit(1);
}static void tcp_send(int handle, void *buffer, size_t len)
{if (send(handle, (char *) buffer, len, 0) == -1)derp((char *) "send");
}static void tcp_recv(int handle, void *buffer, size_t len)
{printf(" - reading %d bytes: ", (int) len);fflush(stdout);size_t len_recd = 0;while (len_recd < len){size_t bytes = recv(handle, (char *) buffer + len_recd, len - len_recd, 0);if (bytes == 0)break; //  Peer has shutdownprintf(" [%d]", (int) bytes);fflush(stdout);if (bytes == -1)derp((char *) "recv");len_recd += bytes;}printf("\n");fflush(stdout);
}static void zmtp_recv(int handle, zmtp_msg_t *msg)
{tcp_recv(handle, (uint8_t *) msg, 2);tcp_recv(handle, msg->data, msg->size);
}static void zmtp_send(int handle, zmtp_msg_t *msg)
{tcp_send(handle, (uint8_t *) msg, msg->size + 2);
}//  This is the 3.0 greeting (64 bytes)
typedef struct
{uint8_t signature[10];uint8_t version[2];uint8_t mechanism[20];uint8_t as_server[1];uint8_t filler[31];
} zmtp_greeting_t;int main(void)
{puts("I: starting subscriber");WSADATA wsData;if (WSAStartup(MAKEWORD(2, 2), &wsData) != 0){std::cerr << "无法初始化Winsock" << std::endl;return 1;}//  Create TCP socketint peer;if ((peer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)derp((char *) "socket");const char *serverIP   = "127.0.0.1";const int   serverPort = 5559;sockaddr_in serverAddress {};serverAddress.sin_family = AF_INET;serverAddress.sin_port   = htons(serverPort);if (inet_pton(AF_INET, serverIP, &(serverAddress.sin_addr)) <= 0){std::cerr << "无效的服务器IP地址" << std::endl;closesocket(peer);WSACleanup();return 1;}//  Keep trying to connect until we succeedputs("I: waiting for connection");while (connect(peer, reinterpret_cast<sockaddr *>(&serverAddress), sizeof(serverAddress)) == -1)Sleep(1);puts("I: connected OK");//  This is our greeting (64 octets)zmtp_greeting_t outgoing = {{0xFF, 0, 0, 0, 0, 0, 0, 0, 1, 0x7F},{3, 0},{'N', 'U', 'L', 'L', 0},{0},{0}};//  Do full backwards version detection following RFC23//  Send first ten bytes of greeting to peertcp_send(peer, &outgoing, 10);//  Read first byte from peerzmtp_greeting_t incoming;tcp_recv(peer, &incoming, 1);uint8_t length = incoming.signature[0];if (length != 0xFF){puts("E: signature not valid (1)");closesocket(peer);exit(0);}//  Looks like 2.0+, read 9 more bytes to be suretcp_recv(peer, (uint8_t *) &incoming + 1, 9);if ((incoming.signature[9] & 1) != 1){puts("E: signature not valid (2)");closesocket(peer);exit(0);}//  Exchange major version numbersputs("I: signature valid, exchanging major versions");tcp_send(peer, (uint8_t *) &outgoing + 10, 1);tcp_recv(peer, (uint8_t *) &incoming + 10, 1);if (incoming.version[0] >= 3){//  If version >= 3, the peer is using ZMTP 3.0, so send//  rest of the greeting and continue with ZMTP 3.0.puts("I: peer is talking ZMTP 3.0");puts("I: sending rest of greeting...");tcp_send(peer, (uint8_t *) &outgoing + 11, 53);//  Get remainder of greeting from peerputs("I: waiting for greeting from peer...");tcp_recv(peer, (uint8_t *) &incoming + 11, 53);//  Do NULL handshake - send READY command//  For now, empty dictionaryputs("I: have full greeting from peer");zmtp_msg_t  ready = {0x04, 0x19};std::string data;data.push_back(0x05);data.append("READY");data.push_back(0x0b);data.append("Socket-Type");int         netByteOrderSize = htonl(3);const char *valueBytes       = reinterpret_cast<const char *>(&netByteOrderSize);data.append(valueBytes, sizeof(netByteOrderSize));data.append("SUB");memcpy(ready.data, data.c_str(), data.size());puts("I: sending READY");zmtp_send(peer, &ready);//  Now wait for peer's READY commandputs("I: expecting READY from peer");zmtp_recv(peer, &ready);//assert(memcmp(ready.data, "READY   ", 8) == 0);puts("I: OK! NULL security handshake completed");puts("I: send sub command");zmtp_msg_t subCmd {0x00, 0x01};subCmd.data[0] = 0x01;zmtp_send(peer, &subCmd);}else{puts("E: major version not valid");closesocket(peer);exit(0);}puts("I: READY, printing messages");while (true){zmtp_msg_t msg;zmtp_recv(peer, &msg);msg.data[msg.size] = 0;puts((char *) msg.data);}closesocket(peer);return 0;
}

相关文章:

ZMTP协议

ZoreMQ Transport Protocol是一个传输层协议&#xff0c;用于ZMQ的连接的信息交互&#xff0c;本文档描述的是3.0协议&#xff0c;主要分析基于NULL Security Mechanism 协议语法 ZMTP由三部分组成&#xff0c;分别是 greeting、handshake、traffic 部分描述构成greeting描述…...

ubuntu18安装中文环境

1. 安装中文语言包 首先&#xff0c;我们需要安装中文语言包。打开终端&#xff0c;输入以下命令&#xff1a; sudo apt-get install language-pack-zh-hans 这个命令会下载并安装中文语言包。安装完成后&#xff0c;我们需要重新启动系统(reboot)。 2. 安装中文输入法 安…...

怎么提取视频中的音乐保存到本地?其实方法很简单

当你想要使用视频中的音乐时&#xff0c;你可以考虑将它从视频中提取出来。这可以用于制作音频样本集&#xff0c;制作铃声或其他音频素材&#xff0c;或者向其他人展示视频的音乐部分而无需显示视频本身。如果你是一位音乐制作人员&#xff0c;你可能会需要一些特定类型的音效…...

线性代数的学习和整理18:矩阵的秩的各种定理, 秩和维度(未完成)

目录 1 矩阵的秩 矩阵的秩 2 求秩的方法 矩阵的维度秩 矩阵的维度 向量的模&#xff0c;矩阵的模-没有把&#xff0c;难道是面积&#xff1f; 矩阵的平直概念 5 矩阵的初等变换&#xff08;矩阵等价概念的引出&#xff09; 1 为什么要引入矩阵的“秩” 这个概念&#x…...

UVa11374 Airport Express(Dijkstra)

题意 给出经济路线以及商业路线&#xff0c;在给出起始点s&#xff0c;终止点e&#xff0c;在只能使用其中一个商业路线 的情况下输出最短路径 思路 如果选择商业路线为从u到v&#xff0c;则需要从s->u,u->v&#xff0c;v->e点的路径最短。使用Dijkstra计算出从s点…...

hadoop的hdfs中避免因节点掉线产生网络风暴

hadoop的hdfs中避免因节点掉线产生网络风暴 控制节点掉线RPC风暴的参数 三个参数都是hdfs-site.xml中参数&#xff0c;具体可以参考apache hadoop官网&#xff0c;其实块的复制速度有两个方面决定&#xff0c;一是namenode分发任务的速度&#xff0c;二则是datanode之间进行复…...

2023年高教社杯 国赛数学建模思路 - 案例:最短时间生产计划安排

文章目录 0 赛题思路1 模型描述2 实例2.1 问题描述2.2 数学模型2.2.1 模型流程2.2.2 符号约定2.2.3 求解模型 2.3 相关代码2.4 模型求解结果 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 最短时…...

Spring MVC介绍

MVC模式是什么 MVC 模式&#xff0c;全称为 Model-View-Controller&#xff08;模型-视图-控制器&#xff09;模式&#xff0c;它是一种软件架构模式&#xff0c;其目标是将软件的用户界面&#xff08;即前台页面&#xff09;和业务逻辑分离&#xff0c;使代码具有更高的可扩展…...

5年测试在职经验之谈:2年功能测试、3年自动化测试,从入门到不可自拔...

毕业3年了&#xff0c;学的是环境工程专业&#xff0c;毕业后零基础转行做软件测试。 已近从事测试行业8年了&#xff0c;自己也从事过2年的手工测试&#xff0c;从事期间越来越觉得如果一直在手工测试的道路上前进&#xff0c;并不会有很大的发展&#xff0c;所以通过自己的努…...

【Python数据分析】数据分析之numpy基础

实验环境&#xff1a;建立在Python3的基础之上 numpy提供了一种数据类型&#xff0c;提供了数据分析的运算基础&#xff0c;安装方式 pip install numpy导入numpy到python项目 import numpy as np本文以案例的方式展示numpy的基本语法&#xff0c;没有介绍语法的细枝末节&am…...

Swift 如何从图片数据(Data)检测原图片类型?

功能需求 如果我们之前把图片对应的数据(Data)保持在内存或数据库中,那么怎么从 Data 对象检测出原来图片的类型呢? 如上图所示:我们将 11 张不同类型的图片转换为 Data 数据,然后从 Data 对象正确检测出了原图片类型。 目前,我们的代码可以检测出 jpeg(jpg), tiff,…...

【ES6】 JavaScript 中的Object.assign

Object.assign() 是 JavaScript 中的一个方法&#xff0c;它用于复制源对象的所有可枚举属性到目标对象。该方法会返回目标对象。 这是其基本用法&#xff1a; let target Object.assign({}, source);在这个例子中&#xff0c;source 对象的所有可枚举属性都被复制到了 targ…...

Redis缓存和持久化

目录 Redis缓存 什么是缓存 缓存更新策略​编辑 业务场景 缓存穿透 常见的解决方案 缓存雪崩 解决方案 缓存击穿 解决方案 Redis持久化 RDB持久化 执行时机 RDB方式bgsave的基本流程 AOF持久化 RDB和AOF的对比​编辑 Redis主从 数据同步原理 总结 Redis缓存 …...

OpenCV(六):多通道分离与合并

目录 1.多通道分离split() 2.多通道合并merge() 3.Android JNI demo 1.多通道分离split() void cv::split ( InputArray m, OutputArrayOfArrays mv &#xff09; m:待分离的多通道图像。 mv:分离后的单通道图像&#xff0c;为向量vector形式。 2.多通道合并merge…...

Sql单行数据查询为多行

数据量小可以&#xff0c;数据量大时间太久 select distinct regexp_substr("fixed_option", [^,],1,level) c1 from "MATERIAL"."BasicInfo_Dishes_Summary" A where "fixed_option" is not NULL AND "dish_name"地三鲜…...

网络协议分析-http/https/tcp/udp

文章目录 TCP三次握手/TCP三次挥手TCP三次握手TCP四次挥手完整报文 实例代码HttpSampleClientHttpSampleServerHttpsSampleClientHttpsSampleServerTcpSampleClientTcpSampleServerUdpSampleClientUdpSampleSever 资料 TCP三次握手/TCP三次挥手 “三次握手”的目的是“为了防止…...

基于aarch64分析kernel源码 四:printk 内核打印

一、参考 Message logging with printk — The Linux Kernel documentation 如何获得正确的printk格式占位符 — The Linux Kernel documentation 使用printk记录消息 — The Linux Kernel documentation printk 内核打印 – 人人都懂物联网 (getiot.tech) 内核printk原理…...

机器人中的数值优化(六)—— 线搜索最速下降法

本系列文章主要是我在学习《数值优化》过程中的一些笔记和相关思考&#xff0c;主要的学习资料是深蓝学院的课程《机器人中的数值优化》和高立编著的《数值最优化方法》等&#xff0c;本系列文章篇数较多&#xff0c;不定期更新&#xff0c;上半部分介绍无约束优化&#xff0c;…...

postman调试注意事项

Postman是一个强大的API调试工具&#xff0c;它可以帮助开发人员测试和调试API端点&#xff0c;以确保它们按预期工作。在使用Postman进行接口调试时&#xff0c;以下是一些注意事项和可能出现的问题&#xff0c;以及如何解决这些问题。 确保请求参数正确 在测试API接口时&am…...

【C#】泛型

【C#】泛型 泛型是什么 泛型是将类型作为参数传递给类、结构、接口和方法&#xff0c;这些参数相当于类型占位符。当我们定义类或方法时使用占位符代替变量类型&#xff0c;真正使用时再具体指定数据类型&#xff0c;以此来达到代码重用目的。 泛型特点 提高代码重用性一定…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

IGP(Interior Gateway Protocol,内部网关协议)

IGP&#xff08;Interior Gateway Protocol&#xff0c;内部网关协议&#xff09; 是一种用于在一个自治系统&#xff08;AS&#xff09;内部传递路由信息的路由协议&#xff0c;主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案

JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停​​ 1. ​​安全点(Safepoint)阻塞​​ ​​现象​​:JVM暂停但无GC日志,日志显示No GCs detected。​​原因​​:JVM等待所有线程进入安全点(如…...