TeamTalk消息协议

article/2025/8/30 2:58:31

数据通讯格式封装协议 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编码后的表示
00
-11
12
-23
21474836474294967294
-21474836484294967295

使用 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

数据类型的表示如下:

类型含义用于哪些数据类型
0Varintint32, int64, uint32, uint64, sint32, sint64, bool, enum
164-bitfixed64, sfixed64, double
2Length-delimitedstring, bytes, embedded messages, packed repeated fields
3Start groupgroups (deprecated)
4End groupgroups (deprecated)
532-bitfixed32, 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 修改对应反序列化代码即可


http://chatgpt.dhexx.cn/article/fWhQxSvH.shtml

相关文章

TeamTalk源码分析(1)

一、TeamTalk服务器端以下部署程序&#xff1a; db_proxy_server、file_server、http_msg_server、login_server、msfs、msg_server、push_server、router_server 各个服务程序的作用描述如下&#xff1a; LoginServer (C): 负载均衡服务器&#xff0c;分配一个负载小的MsgSe…

把TeamTalk(即时通讯项目)中的线程池连接池拆出来单独测试。

研究过Teamtalk的伙伴会发现它的线程池和连接池与很多文件有关联&#xff0c; 这篇文章主要写&#xff0c;把它的线程池连接池拆出来需要用到哪些文件。 其实我本来只想测试它的连接池的&#xff0c;但发现连接池里套的有线程池&#xff0c;于是就一起拆出来了。 整个工程的树…

teamtalk原理

再贴一遍架构图 从图中可以看出&#xff0c;对外使用的是http连接&#xff0c;内部使用的是tcp长连接。 类的命名规则&#xff1a;xxxServConn是模块连别的模块&#xff0c;xxxConn是别的模块连它。 协议设计 teamtalk采用protobuf进行序列化 typedef struct {uint32_t le…

TeamTalk源码分析(一)—— TeamTalk介绍

TeamTalk是蘑菇街开源的一款企业内部用的即时通讯软件&#xff08;Enterprise IM&#xff09;&#xff0c;类似腾讯的RTX。网上也有很多的介绍&#xff0c;我这里也有写几遍关于这款产品的“流水账”&#xff0c;一方面对自己这段时间的阅读其代码做个总结&#xff0c;尽量做个…

teamtalk实现即时通讯

即时通讯技术应用非常广泛&#xff0c;涉及教育、电商、金融、泛娱乐、生活服务、医疗健康、政企服务、游戏聊天、在线客服等等行业&#xff0c;不是大家认为仅仅是qq、微信那样。 即时通讯架构 先给张图 客户端与服务器端进行网络通信、收发消息连接层为客户端收发消息提供…

通识哈夫曼树及其应用,一起来构造属于自己的哈夫曼树

1.哈夫曼树的背景 哈夫曼&#xff08;霍夫曼、赫夫曼&#xff09;David Albert Huffman(August9,1925-October7,1999)。计算机科学的先驱&#xff0c;以他的哈夫曼编码闻名&#xff0c;在他的一生中&#xff0c;对于有限状态自动机&#xff0c;开关电路&#xff0c;异步过程和信…

哈佛结构冯·诺依曼结构

哈佛结构是一种将程序指令存储和 数据存储分开的存储器结构。哈佛结构是 一种并行体系结构&#xff0c;它的主要特点是将程序和数据存储在不同的存储空间中&#xff0c;即程序存储器和数据存储器是两个独立的存储器&#xff0c;每个存储器独立编址、独立访问。 冯诺依曼结构也…

微型计算机之哈佛架构是什么?

“哈佛体系结构”指的是什么&#xff1f; 微型计算机处理命令和数据&#xff0c;但是在很久以前的微型计算机中&#xff0c;用命令和数据共享了一条总线。在这种情况下&#xff0c;CPU在读取指令时使用总线&#xff0c;因此无法访问数据&#xff0c;并且在读取指令结束后访问数…

冯诺依曼结构、哈佛结构、改进型哈佛结构

冯诺依曼结构 冯诺依曼结构&#xff0c;又称为普林斯顿体系结构&#xff0c;是一种将程序指令存储器和数据存储器合并在一起的存储器结构。取指令和取操作数都在同一总线上&#xff0c;通过分时复用的方式进行&#xff1b;缺点是在高速运行时&#xff0c;不能达到同时取指令和…

高级数据结构之赫夫曼树

思考两个问题 电报发送&#xff1a;二战的时候大家都知道那时候普遍会应用电报&#xff0c;如果让你来设计一个电报的发送编码你该如何设计呢&#xff1f; 电报加密后越短越好&#xff0c;发送快。破解难解码容易换加密树也要快可逆的 压缩算法&#xff1a;给你10000个字符&am…

ARM到底是冯诺依曼结构还是哈佛结构?

问题 嵌入式的学习中ARM处理器是主题&#xff0c;这些年产业界除了PC和服务器市场外&#xff0c;以手机、pad、家电控制等为代表的嵌入式领域都被ARM几乎垄断了。所以学习嵌入式处理器&#xff0c;其实等同于学习ARM。&#xff08;当然了&#xff0c;近两年RISC-V架构横空出世在…

冯诺依曼结构和哈佛结构的区别

冯诺依曼结构和哈佛结构的区别 1. 冯诺依曼结构&#xff1a; 说明&#xff1a; 一种将程序指令存储器和数据存储器合并在一起的存储器结构。程序指令存储地址和数据存储地址指向同一个存储器的不同物理位置&#xff0c;因此程序指令和数据的宽度相同。 冯诺依曼的计算机必须…

冯诺依曼与哈佛结构的区别

cortex M3,M4主要采用哈弗结构 个人理解&#xff1a;最主要的区别在于程序空间和数据空间是否是一体的&#xff0c;冯诺依曼结构数据空间和地址空间是不分开的&#xff0c;而哈佛结构数据空间和地址空间是分开的 哈弗结构的优势&#xff1a;如果采用流水线设计&#xff0…

冯氏结构、哈佛结构、超级哈佛结构之间的异同

冯.诺伊曼结构 1945年&#xff0c;冯.诺伊曼首先提出了“存储程序”的概念和二进制原理&#xff0c;后来&#xff0c;人们把利用这种概念和原理设计的电子计算机系统统称为“冯.诺伊曼型结构”计算机。冯.诺伊曼结构的处理器使用同一个存储器&#xff0c;经由同一个总线传输…

哈佛结构

数字信号处理一般需要较大的运算量和较高的运算速度&#xff0c;为了提高数据吞吐量&#xff0c;在数字信号处理器中大多采用哈佛结构&#xff0c;如下图所示 图 哈佛结构 与冯.诺曼结构处理器比较&#xff0c;哈佛结构处理器有两个明显的特点&#xff1a; 使用两个独立的存储…

冯诺依曼体系结构、哈佛体系结构与改进型哈佛结构之间的区别

1、冯诺依曼结构  冯诺依曼结构又称作普林斯顿体系结构&#xff08;Princetionarchitecture&#xff09;。  1945年&#xff0c;冯诺依曼首先提出了“存储程序”的概念和二进制原理&#xff0c;后来&#xff0c;人们把利用这种概念和原理设计的电子计算机系统统称为“冯诺依…

哈佛结构与冯诺依曼结构(含STM32系统结构解析)

存储器是微控制器的重要组成部分&#xff0c;不同类型的微控制器其采用的存储结构与容量不尽相同&#xff0c;但存储器的用途是相同的&#xff0c;用于存放程序和数据。微控制器中的存储结构有两种基本构成形式。 冯诺依曼结构 冯诺依曼结构也称普林斯顿结构&#xff0c;是一…

STM32属于哈佛结构还是冯诺依曼结构?

目录 01、冯诺依曼体系 02、哈佛体系 03、arm和哈佛、冯诺依曼的关系 04、实际芯片制造 现代的CPU基本上归为冯诺伊曼结构&#xff08;也成普林斯顿结构&#xff09;和哈佛结构。 冯洛伊曼结构就是我们所说的X86架构&#xff0c;而哈佛结构就是ARM架构。一个广泛用于桌面端…

哈佛体系结构

哈佛机&#xff1a;为数据和程序提供了格子独立的存储器。 程序计数器只指向程序存储器&#xff0c;而不指向数据存储器&#xff0c;这样的的后果是很难再哈佛机上编写出一个自修改的程序。独立的程序存储器和数据存储器为数字信号处理提供了较高的性能。结构如下图所示&#x…

哈佛结构和冯诺依曼结构?STM32属于哈佛结构还是冯诺依曼结构?

现代的CPU基本上归为冯诺伊曼结构&#xff08;也成普林斯顿结构&#xff09;和哈佛结构。 冯诺依曼体系 冯诺依曼体系结构图如下 冯诺依曼结构也称普林斯顿结构&#xff0c;是一种将程序指令存储器和数据存储器合并在一起的存储器结构。数据与指令都存储在同一存储区中&…