MM2协议简介
MM2协议简介 |
MM2协议采用TCP协议承载,二进制编码格式。除握手消息和心跳消息外,其它消息结构分为MM2协议头部和业务消息体两部分。
1、MM2消息头定义为定长字段,字段定义固定总长度为(28个字节)。包括:
Length:消息总长度(4个字节)
MessageType:消息类型(4个字节)
SourceModuleType:源模块类型(2个字节)
SourceModuleID:源模块ID(2个字节)
SourceManagerType:源Manager类型(2个字节)
SourceManagerID:源ManagerID(2个字节)
TargetModuleType:目的模块类型(2个字节)
TargetModuleID:目的模块ID(2个字节)
TargetManagerType:目的ManagerType(2个字节)
TargetManagerID:目的ManagerID(2个字节)
SequenceID:由发送方填写,请求和响应消息必须保持一致(4个字节)
2、MM2消息体定义:
数据类型 是否是必填数据 编码方式 说明
定长数据 是 直接将数据内容写入消息体
定长数据 可选字段 可选标识+数据内容(如果内容存在) 可选字段为1BYTE,0标识不存在,1标识存在,后面跟数据内容。
变长数据 是 长度+数据内容 长度为4个字节
变长数据 可选字段 可选标识+长度+数据内容
上表中的’+’在实际码流中不存在,仅表示顺序关系。
3、通信过程:
MM2协议采用TCP协议承载,支持TCP长连接,不支持TCP短连接。
首先客户端向服务器端发起TCP连接请求建立TCP连接。
TCP连接建立后,客户端向服务器端发送握手请求消息。握手请求消息中包含有客户端的能力信息,服务器端如果允许客户端握手,则返回握手成功响应消息,握手成功响应消息中包含服务器的能力信息。如果握手失败,则服务器返回握手失败响应。重连间隔时间默认为5秒,可修改。
MM2连接建立成功之后,双方需要互相发送心跳消息维持连接。心跳消息没有响应。对于任何一方,如果发现在一段时间内没有收到对端发送过来的任何数据(注意:包括心跳消息、业务消息等任何消息)则主动断开连接,并尝试重连。心跳超时时间应设置大于对端的心跳发送间隔时间。默认设置:心跳间隔时间=2秒,心跳超时时间=心跳间隔时间*2。
MM2协议特点 |
1. 高效
主要体现为:
(1) 长连接
由于Socket连接的建立和关闭很耗性能,所以MM2只建立一次连接,并把连接一致保持着。所谓的多路复用。
缺点:容易出现断连,
可以通过 netstat –na | grep (portId)
命令来判断是否连接(有3种状态:LISTEN(监听)、ESTABLISHED(连接)和TIME_WAIT(等待))
(2) 约定大于配置
如模块双方通信,一方按照某一顺序封装发送消息,另一方则必须严格按照这个顺序进行读取。可以从MM2协议里看出MM2并没有将基本字段类型和结构体一些附加信息写入传输流中,都是通过约束来完成,这样达到了节省了传输负载,提供性能。
缺点:缺乏灵活性,易出去接口不同步。
可通过tcpdump –i lo tcp port (portId) –Xo 10000 –vv
命令抓包进行问题的确认。
(3) 二进制传输
优点:节省流量,性能提高了。
2. 安全
(1) 心跳消息
心跳消息无需响应,由连着的双方互发消息。
(2) 握手消息
在建立Socket连接的时候,发送握手消息,进行身份的确认,确认成功才会进行后续的操作。
握手消息由客户端发起,服务端返回相应的响应消息。
3. 异构性
MM2协议中只规定了基本类型如何表示,所以不同编程语言实现的模块可以通过MM2协议来交互。
4. 支持各种编解码
5. 支持集合、数组、自定义结构体。
其中集合和数据是通过一个特殊的4字节标识来表示。
MM2和java序列化的性能比较 |
1、MM2和java序列化的性能比较
示例代码:
//序列化对象
TestSerializable ts = new TestSerializable("1001","zhangshun");
long time = System.currentTimeMillis();
ByteArrayOutputStream baos = new ByteArrayOutputStream();;
ObjectOutputStream oos = null;
for (int i = 0; i < 100000; i++)
{
try
{
oos = new ObjectOutputStream(baos);
oos.writeObject(ts);
}
catch (IOException e)
{
e.printStackTrace();
}
}
System.out.println("serialize length="+baos.toByteArray().length/(1024*1024) +" M");
System.out.println("serialize used time:" + (System.currentTimeMillis() - time) +"ms");
time = System.currentTimeMillis();
//MM2编码封装对象
TestMM2 tmm = new TestMM2("1001","zhangshun");
long mmLength = 0;
for (int i = 0; i < 100000; i++)
{
byte[] bb = tmm.toByte();
mmLength += bb.length + 28; //28为MM2头长度
}
System.out.println("mm2 length = " + mmLength/(1024*1024) + " M");
System.out.println("mm2 used time:" + (System.currentTimeMillis() - time) +"ms");
运行结果:
serialize length=9 M
serialize used time:1875ms
mm2 length = 4 M
mm2 used time:375ms
从中可以看出MM2性能无论是从时间还是空间都要优于java序列化.