MongoDB 是由 MongoDB Inc 开发的 NoSQL 数据库,它是无模式的。它是使用 c++ 和 javascript 设计和创建的,允许更高的连接性。

MongoDB 是一个 NoSQL Server,其中数据存储在 BSON(二进制 JSON)文档中,每个文档本质上都建立在键值对结构上。由于 MongoDB 很容易存储无模式数据,因此使其适合捕获结构未知的数据。

MongoDB Wire Protocol

MongoDB Wire Protocol 是一个简单的基于套接字的请求-响应式协议。 客户端通过常规 TCP/IP 套接字与数据库服务器通信。通常,Mongo 使用 TCP 作为其传输协议。 Mongo 流量的著名 TCP 端口是 27017。

MongoDB 将数据记录存储为 BSON 文档。 BSON 是 JSON 文档的二进制表示,尽管它包含比 JSON 更多的数据类型。


MongoDB 文档由字段-值对组成。

Mongo 消息类型和格式

MongoDB 对客户端请求和数据库回复都使用 OP_MSG 操作码。

#define OP_REPLY           1
#define OP_MESSAGE      1000
#define OP_UPDATE       2001
#define OP_INSERT       2002
#define OP_RESERVED     2003
#define OP_QUERY        2004
#define OP_GET_MORE     2005
#define OP_DELETE       2006
#define OP_KILL_CURSORS 2007
#define OP_COMMAND      2010
#define OP_COMMANDREPLY 2011
#define OP_COMPRESSED   2012
#define OP_MSG          2013
{ OP_REPLY,  "Reply" },
{ OP_MESSAGE, "Message" },
{ OP_UPDATE,  "Update document" },
{ OP_INSERT,  "Insert document" },
{ OP_RESERVED,"Reserved" },
{ OP_QUERY,  "Query" },
{ OP_GET_MORE,  "Get More" },
{ OP_DELETE,  "Delete document" },
{ OP_KILL_CURSORS,  "Kill Cursors" },
{ OP_COMMAND,  "Command Request" },
{ OP_COMMANDREPLY,  "Command Reply" },
{ OP_COMPRESSED,  "Compressed Data" },
{ OP_MSG,  "Extensible Message Format" },

Mongo 标准消息头

通常,每条消息都由一个标准消息头和请求特定的数据组成。

消息长度:消息的总大小(以字节为单位)。 这个总数包括保存消息长度的 4 个字节。
请求ID:唯一标识消息的客户端或数据库生成的标识符。
响应:从客户端的消息中获取的 requestID。
操作码:消息类型。

Query 消息

OP_QUERY消息用于在数据库中查询集合中的文档。
messageLength: 报文总长度,使用 4 个字节表示。
requestID : 由客户端或服务器生成的报文唯一标识。 例如客户端请求 (OP_QUERY 和 OP_GET_MORE), 将返回 OP_REPLY 报文给 responseTo 字段表示的请求. 客户端可以使用 requestID 和 responseTo 字段关联查询响应到原始请求上。
responseTo : 服务端响应使用此字段关联到 requestID 对应的查询请求上。
opCode: 报文类型。
fullCollectionName: 完整的集合名称;即命名空间。
number To Skip:要跳过的文件数
number To Return:表示第一个 OP_REPLY 响应中的文档返回数

Reply 消息

该OP_REPLY消息由数据库发送,以响应OP_QUERY或OP_GET_MORE消息。

cursorID :会在 OP_REPLY 中设置
number Return:返回的文档数量
document: 一个或多个要插入到集合中的文档。如果有多个,它们会依次写入到插槽中。

Insert document 消息

OP_INSERT消息用于将一个或多个文档插入到集合中。

document: 一个或多个要插入到集合中的文档。如果有多个,它们会依次写入到插槽中。

fullCollectionName:完整的集合名称;即命名空间。完整的集合名称是数据库名称与集合名称.的拼接,使用一个for concatenation。例如,对于数据库foo和集合bar,完整的集合名称是foo.bar。

Update document 消息

OP_UPDATE消息用于更新集合中的文档。

ZERO: 0 - 保留给以后使用
selector:文档查询条件,BSON文档,指定要更新的文档的选择查询。
update: 指定要执行的更新

Delete document 消息

OP_DELETE消息用于从集合中删除一个或多个文档。

ZERO:整数值为0.保留以备将来使用。
selector:代表用于选择要删除的文档的查询的BSON文档。选择器将包含一个或多个元素,所有这些元素都必须与要从集合中移除的文档匹配。

Get More 消息

OP_GET_MORE消息用于在数据库中查询集合中的文档。

ZERO: 0 - 保留给以后使用
number To Return: 返回的文档数量,如果numberToReturn是0,数据库将使用默认的返回大小。
curso rID :会在 OP_REPLY 中设置

数据库将用OP_REPLY消息响应OP_GET_MORE消息。

Kill Cursors 消息

OP_KILL_CURSORS消息用于关闭数据库中的活动光标。这是确保在查询结束时回收数据库资源所必需的。

ZERO:整数值为0.保留以备将来使用。
numberOfCursorIDs:消息中的光标ID的数量。
cursorIDs:游标ID的“数组”被关闭。如果有多个,它们会依次写入到插槽中。

如果游标被读取直到耗尽(读取直到OP_QUERY或OP_GET_MORE为游标ID返回0),则不需要终止游标。

MongoDB数据库协议解析及C/C++代码实现

...
static int dissect_opcode_types(u_char *mongo_data, unsigned int offset, unsigned int opcode, int message_length)
{if(opcode == 1){printf("Response :");}else{printf("Request :");}printf("%s\n", val_to_str_const(opcode, opcode_vals, "Unknown"));    switch(opcode){case OP_REPLY:offset = dissect_mongo_reply(mongo_data, offset, message_length);break;case OP_MESSAGE:offset = dissect_mongo_msg(mongo_data, offset, message_length);break;case OP_UPDATE:offset = dissect_mongo_update(mongo_data, offset, message_length);break;case OP_INSERT:offset = dissect_mongo_insert(mongo_data, offset, message_length);break;case OP_QUERY:offset = dissect_mongo_query(mongo_data, offset, message_length);break;case OP_GET_MORE:offset = dissect_mongo_getmore(mongo_data, offset, message_length);break;case OP_DELETE:offset = dissect_mongo_delete(mongo_data, offset, message_length);break;case OP_KILL_CURSORS:offset = dissect_mongo_kill_cursors(mongo_data, offset, message_length);break;case OP_COMMAND:offset = dissect_mongo_op_command(mongo_data, offset, message_length);break;case OP_COMMANDREPLY:offset = dissect_mongo_op_commandreply(mongo_data, offset, message_length);break;case OP_COMPRESSED:offset = dissect_mongo_op_compressed(mongo_data, offset, message_length);break;case OP_MSG:offset = dissect_mongo_op_msg(mongo_data, offset, message_length);break;default:/* No default Action */break;}return offset;
}
....
int main(int argc, char* argv[])
{char errbuf[1024];pcap_t *desc = 0;char *filename = argv[1];if (argc != 2){printf("usage: ./dissect_mongo [pcap file]\n");return -1;}printf("ProcessFile: process file: %s\n", filename);if ((desc = pcap_open_offline(filename, errbuf)) == NULL){   printf("pcap_open_offline: %s error!\n", filename);return -1; }   pcap_loop(desc, pkt_number, (pcap_handler)ace_pcap_hand, NULL);pcap_close(desc);return 0;
}

运行结果:



总结

MongoDB Wire Protocol是一个简单的基于socket,请求/响应方式的协议,客户端使用常规的TCP/IP套接字(socket)进行通信,服务端默认监听端口是 27017。

参考:https://www.mongodb.com/docs/manual/reference/mongodb-wire-protocol/

MongoDB数据库协议解析及C/C++代码实现相关推荐

  1. Oracle(TNS)协议解析及C/C++代码解析

    Oracle客户端和服务器使用TNS作为其数据交换协议. 它提供了一种对用户透明的层, 为不同的工业标准协议提供统一, 通用的接口. 基本上是TNS以这样的方式指定了端口1521上的会话是" ...

  2. TFTP协议解析及C/C++代码实现

    TFTP 用于以非常简单的方式传输文件.与其他文件传输协议(如:FTP 或 HTTP)相比,TFTP 更简单,代码量也更小,因此更易于实现. 通常,TFTP 使用 UDP 作为其传输协议.众所周知的 ...

  3. UDT协议解析及C/C++代码实现

    基于 UDP 的协议 (UDT) 是一种高性能数据传输协议.用于广域高速网络上的分布式数据密集型应用程序. UDT 使用 UDP 传输具有自己的可靠性控制和拥塞控制机制的批量数据. 新协议可以以比 T ...

  4. MySQL协议解析及C/C++代码实现

    MySQL 常用于许多知名网站,包括 Facebook.Google.Twitter 和 YouTube等等.它于 1995 年首次发布.MySQL 是用 C 和 C++ 编写的. MySQL 适用于 ...

  5. SMTP协议解析及C/C++代码实现

    SMTP 是一种应用层协议. 要发送邮件的客户端打开到 SMTP 服务器的 TCP 连接,然后通过该连接发送邮件. SMTP 服务器是一种永远在线的侦听模式. 一旦它侦听来自任何客户端的 TCP 连接 ...

  6. 英雄远征Erlang源码分析(5)-协议解析与玩家登录处理

    现在,客户端与服务器的连接算是正式建立了,此时用户需要做的第一件事就是登陆.不过在登录之前,我们要先研究下前后端通信的协议. 客户端与服务端建立连接后,通过提前制定好的协议进行交互.具体的协议文档在d ...

  7. java 读取mysql数据库_原生Java操作mysql数据库过程解析

    这篇文章主要介绍了原生Java操作mysql数据库过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.引入数据库驱动的jar包 以通过mav ...

  8. 后端代码之服务端 - MongoDB数据库的连接、重启测试与(Studio3T)查看 - 讲解篇

    文章目录 前言 一. 在项目中安装Mongoose中间件 二. 安装完毕,新建一个路由作为测试路由 通过WebStorm软件,打开项目,编辑index.js文件: 三.重启服务,浏览器查看:测试连接是 ...

  9. wireshark解析达梦数据库协议

    达梦数据库不开源,所以wireshark没有对应的协议解析,可实际工作中又需要抓包验证程序处理流程是否正确,为了校验起来方便,自己手撸一个达梦的解析脚本. 先来展示一下解析结果: 解析脚本:damen ...

最新文章

  1. Node.js + Nginx-现在怎么办?
  2. TfidfVectorizer中的参数norm默认值是l2
  3. c++17(33)-数值上下限、无穷、非数、中文字符串
  4. 时间计算题100道_2019四校及分校自招开放日情况汇总(含时间安排、考试内容难度、到场人数等)...
  5. C语言中Uint8_t数据类型
  6. 继承演练 c# 1613706361
  7. Android 呼吸灯流程分析
  8. 6. Magento2 --- 创建主题
  9. 让 “微软雅黑” 在IE6下完美显示
  10. linux备份没有vmlinuz,解决file /isolinux/vmlinuz0 not found
  11. u盘为什么要安全弹出?丢失的数据怎么恢复?
  12. 模拟电路笔记(一)晶体二极管及其应用
  13. PPC飞信问题...WM6.5版无法安装以及连接
  14. 发展战略-以技术为导向还是以产品为导向的方向选择?
  15. android半透明闪退,移动端常见面试题一:移动端兼容解决方案
  16. 世界在变化刷脸支付一直奋进
  17. 门店私域流量运营怎么做?
  18. JMeter BeanShell 应用
  19. 简简的语法13——副词对动词就像形容词对名词一样
  20. 离散数学 习题篇 —— k倍区间

热门文章

  1. 求平均查找长度(成功+失败)
  2. python基础—for循环(图案打印) 2021-11-06
  3. Kafka 快速入门(安装)
  4. U-boot-1.1.6-2008R1到vdsp5(bf561)的移植记录(16):*cplb_add
  5. Lammps 如何计算速度矢量分布?
  6. android 自定义adapter
  7. 配电室综合监测系统的组网与应用
  8. [转]纯真IP数据库格式详解
  9. wpf中键盘事件中KeyPressEventArgs.Handled 的用法(解决键盘事件默认操作)
  10. 调试maxxaudio 新唐科技效果IC I2C通讯程序