数据通讯格式封装协议 Protocol Buffer

常用序列化方案比较 参考 

https://www.cnblogs.com/johnny666888/p/12841735.html

Protocol Buffer

Protocol Buffer还有一个非常重要的优点就是可以保证同一消息报文新旧版本之间的兼容性

protobuf协议核心思想

基于128bits的数值存储方式(Base 128 Varints)

数据表示方式:每块数据由接连的若干个字节表示(小的数据用1个字节就可以表示),每个字节最高位标识本块数据是否结束(1:未结束,0:结束),低7位表示数据内容。(可以看出数据封包后体积至少增大14.2%)

数字1的表示方法为:0000 0001,这个容易理解

数字300的表示方法为:1010 1100 0000 0010

protobuf字节序是小端字节序,所以这个数字实际是0000 0010 1010 1100

1010 1100 0000 0010

→ 010 1100 000 0010

如下:

000 0010 010 1100

→ 000 0010 ++ 010 1100

→ 10 0101100

→ 256 + 32 + 8 + 4 = 300

基于序号的协议字段映射(类似key-value结构)

所以字段可以乱序,可缺段(记optional)

message person{

required string name = 1;

required string country = 2;

optional int32 age = 3;

}

效果相当于json数据:person= [{1: "john"}, {2: "USA"}, {3: 30}],其中{3: 30} 还可以不传,person还可以传成 [{2: "USA"}, {1: "john"}],对端仍旧可以正常解析。

基于无符号数的带符号数表示(ZigZag 编码)

原始的带符号数 ZigZag编码后的表示
0 0
-1 1
1 2
-2 3
2147483647 4294967294
-2147483648 4294967295

使用 zigzag 编码,充分利用基于128bits的数值存储(Base 128 Varints)的 技术,只需要加多1个位来表示符号。当绝对值小的数字非常有利,这种方式可以有效减少协议内容长度。

sint32类型编码如下:

(n << 1) ^ (n >> 31)

sint64类型编码如下:

(n << 1) ^ (n >> 63)

协议数据结构

protobuf怎么在一长串二进制中表示若干个数据?

做法就是每块数据前加一个数据头,表示数据类型及协议字段序号。

msg1_head + msg1 + msg2_head + msg2 + ...

数据头也是基于128bits的数值存储方式,一般1个字节就可以表示:

message Test1 {

required int32 a =1;

}

如上创建了 Test1 的结构并且把 a 设为 2,序列化好的二进制数据为:

0 000 1000 0 000 0010

以上数据转成十六进制也就是 08 02,其中 8 是怎么得到的?

000 1 000

低3位表示数据类型:0,其他表示协议字段序号:1,加上最高位0, 结果就是8

数据类型的表示如下:

类型 含义 用于哪些数据类型
0 Varint int32, int64, uint32, uint64, sint32, sint64, bool, enum
1 64-bit fixed64, sfixed64, double
2 Length-delimited string, bytes, embedded messages, packed repeated fields
3 Start group groups (deprecated)
4 End group groups (deprecated)
5 32-bit fixed32, sfixed32, float

TeamTalk proto

pb目录下 定义了消息

基础数据结构的定义在IM.BaseDefine.proto中。

见 IM doc文件下协议说明

消息数据流;

如获取部门列表

buildProtoMsg ====>

//封装数据 SID CID
IMBuddy.IMDepartmentReq imDepartmentReq  = IMBuddy.IMDepartmentReq.newBuilder().setUserId(userId).setLatestUpdateTime(lastUpdateTime).build();
int sid = IMBaseDefine.ServiceID.SID_BUDDY_LIST_VALUE;
int cid = IMBaseDefine.BuddyListCmdID.CID_BUDDY_LIST_DEPARTMENT_REQUEST_VALUE;//组装包头 headercom.mogujie.tt.protobuf.base.Header header = new DefaultHeader(sid, cid);int bodySize = requset.getSerializedSize();header.setLength(SysConstant.PROTOCOL_HEADER_LENGTH + bodySize);seqNo = header.getSeqnum();listenerQueue.push(seqNo,packetlistener);boolean sendRes = msgServerThread.sendRequest(requset,header);
//写入bufferDataBuffer headerBuffer = header.encode();DataBuffer bodyBuffer = new DataBuffer();int bodySize = requset.getSerializedSize();bodyBuffer.writeBytes(requset.toByteArray());DataBuffer buffer = new DataBuffer(SysConstant.PROTOCOL_HEADER_LENGTH  + bodySize);buffer.writeDataBuffer(headerBuffer);buffer.writeDataBuffer(bodyBuffer);if (null != buffer && null != channelFuture.getChannel()) {Channel currentChannel =  channelFuture.getChannel();boolean isW = currentChannel.isWritable();boolean isC  = currentChannel.isConnected();if(!(isW && isC)){throw  new RuntimeException("#sendRequest#channel is close!");}
//socket 发送channelFuture.getChannel().write(buffer.getOrignalBuffer());

IM-server接收端

MsgConn.cpp

_HandleClientDepartmentRequest 处理

void CMsgConn::HandlePdu(CImPdu* pPdu)
{// request authorization checkif (pPdu->GetCommandId() != CID_LOGIN_REQ_USERLOGIN && !IsOpen() && IsKickOff()) {log("HandlePdu, wrong msg. ");throw CPduException(pPdu->GetServiceId(), pPdu->GetCommandId(), ERROR_CODE_WRONG_SERVICE_ID, "HandlePdu error, user not login. ");return;}switch (pPdu->GetCommandId()) {case CID_OTHER_HEARTBEAT:_HandleHeartBeat(pPdu);break;//....case CID_BUDDY_LIST_USERS_STATUS_REQUEST:_HandleClientUsersStatusRequest(pPdu);break;case CID_BUDDY_LIST_DEPARTMENT_REQUEST:_HandleClientDepartmentRequest(pPdu);break;// for group processcase CID_GROUP_NORMAL_LIST_REQUEST:s_group_chat->HandleClientGroupNormalRequest(pPdu, this);break;case CID_GROUP_INFO_REQUEST:s_group_chat->HandleClientGroupInfoRequest(pPdu, this);break;case CID_GROUP_CREATE_REQUEST:s_group_chat->HandleClientGroupCreateRequest(pPdu, this);break;case CID_GROUP_CHANGE_MEMBER_REQUEST:s_group_chat->HandleClientGroupChangeMemberRequest(pPdu, this);break;//....default:log("wrong msg, cmd id=%d, user id=%u. ", pPdu->GetCommandId(), GetUserId());break;}
}
void CMsgConn::_HandleClientDepartmentRequest(CImPdu *pPdu)
{//消息检查 时间戳对比数据变更 IM::Buddy::IMDepartmentReq msg;CHECK_PB_PARSE_MSG(msg.ParseFromArray(pPdu->GetBodyData(), pPdu->GetBodyLength()));log("HandleClientDepartmentRequest, user_id=%u, latest_update_time=%u.", GetUserId(), msg.latest_update_time());//数据库CDBServConn* pDBConn = get_db_serv_conn();if (pDBConn) {CDbAttachData attach(ATTACH_TYPE_HANDLE, m_handle, 0);msg.set_user_id(GetUserId());msg.set_attach_data(attach.GetBuffer(), attach.GetLength());pPdu->SetPBMsg(&msg);pDBConn->SendPdu(pPdu);}
}//关键类
//class CDBServConn : public CImPduConn

协议扩展

根据需要修改

BaseDefine.proto等 协议文件  增加相应的业务类型指令 KEY 同时修改server接收端处理业务逻辑 client 修改对应反序列化代码即可

TeamTalk消息协议相关推荐

  1. 互联网协议 — ICMP 互联网控制消息协议

    目录 文章目录 目录 ICMP ICMPv4 协议栈 ICMPv4 的消息类型 Echo Request & Echo Reply Msg Destination Unreachable Ms ...

  2. ICMP (互联网控制消息协议 )是什么

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. 互联网控制消息协议(英语:Internet Control Message Protocol,缩写: ...

  3. 网际控制报文协议icmp_网络中的ICMP(Internet控制消息协议)

    网际控制报文协议icmp ICMP(Internet控制消息协议)简介 (Introduction to ICMP (Internet Control Message Protocol)) IP (I ...

  4. MOTT消息协议的学习

    MOTT消息协议的介绍 MQTT是一个基于客户端-服务器的消息发布/订阅传输协议.MQTT协议是轻量.简单.开放和易于实现的,这些特点使它适用范围非常广泛.在很多情况下,包括受限的环境中,如:机器与机 ...

  5. 消息协议 AMQP 及MQTT ,STOMP,JMS的概念和基本理解

    前言 简单理解 就是需要大家都遵守的 套规 .在计算机领域中,只要涉及不同的计算机之间要共同完成一 事情的时候,就肯定会有协议的存在,就像我们说话用某种语言一样,不 同的计算机之间必 须使用相同的语 ...

  6. 禁止服务器的协议,电脑怎么阻止Internet控制消息协议ICMP?

    电脑完全阻止ICMP绝不是一个好主意,因为它是一个非常有用的协议.ping请求(回显)和超时数据包(由traceroute请求返回)等故障排除工具最好不要单独使用,否则解决简单的网络问题将是未来的噩梦 ...

  7. 架构设计:系统间通信(20)——MQ:消息协议(下)

    (接上文<架构设计:系统间通信(19)--MQ:消息协议(上)>) 上篇文章中我们重点讨论了"协议"的重要性,并为各位读者介绍了Stomp协议和XMPP协议.这两种协议 ...

  8. C#Ping命令【因特网控制消息协议ICMP】

    ICMP协议 ICMP(Internet Control Message Protocol)Internet控制报文协议.它是TCP/IP协议簇的一个子协议,用于在IP主机.路由器之间传递控制消息.控 ...

  9. TeamTalk消息服务器原理及二次开发简介

    置顶:关于用smart pointer修改的demo源码我放在了我的开源中国的git目录下, 这个地址:http://git.oschina.net/benben-de-eggs/tt-code-fr ...

  10. IM即时通讯-3-如何设计消息协议层方案

    1. 前言 上篇即时通讯系列-如何下手做技术方案设计 最后总结出IM系统的端侧基本结构 后续文章将从下到上以此做架构设计. 本文Agenda 什么是消息同步 同步协议的常见设计方案包含哪些 应该采用哪 ...

最新文章

  1. KMP子串匹配算法(Knuth–Morris–Pratt algorithm)
  2. Safari支持Service Worker,PWA还有多久爆发?
  3. mybatis+spring+c3p0+maven+ehcache
  4. 《Scala机器学习》一一1.1 Scala入门
  5. K210系列第一个示例程序
  6. 期刊投稿参考文献格式注意要点
  7. 计算机键盘无法使用怎么处理,为什么键盘不能用 键盘不能用怎么办
  8. Unity 自动化构建方案:一键实现版本管理与打包、压缩
  9. jpeg格式转pdf格式的简单方法
  10. 数组的并集交集和差集
  11. 如何解决Invalid quadratic form: product is complex
  12. 苏嵌实训——day7
  13. 小程序也能接广告了,微信小程序广告位投放指南!
  14. 游苹果山赋——东南子(2010年旧文)
  15. Web 基础——Nginx(二)
  16. Visual Studio 2017 Intro
  17. 祥云杯2022 writeup
  18. 告别消费主义的双12,是华为云12.12会员节真正的意义
  19. vue+iView实现导入与导出excel功能
  20. windows10驱动 x64--- 3环代码加载驱动(二)

热门文章

  1. HTML常见标签及个人简历制作
  2. 黑客Windows攻防初级知识点整合
  3. 输入月份自动生成excel考勤表,周末高亮,内容可以勾选
  4. matlab三轴机械臂,MATLAB 中的机械臂算法——路径规划
  5. Google关停中国区域翻译服务后继续使用Chrome自带翻译插件的方法教程
  6. 虚拟机安装linux系统教程
  7. 金士顿16G优盘变8M恢复教程
  8. linux 查看硬盘健康,linux硬盘检测健康状态
  9. 三国群雄传ol服务器 修改,三国群英传OL DATA.PAK相关修改
  10. .NET报表控件ActiveReports实战应用——入门指南