TeamTalk消息协议

数据通讯格式封装协议 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;

 //组装包头 header
            com.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);
//写入buffer
  DataBuffer 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 check
	if (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 process
		case 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 修改对应反序列化代码即可

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
teamtalk安卓源码是一款开源的即时通讯应用程序的源代码。它基于C++和Java开发,具有跨平台的特性,可以在安卓设备上使用。通过对teamtalk安卓源码的剖析,我们可以深入了解其工作原理和实现细节。 首先,在剖析过程中,我们会看到teamtalk安卓源码的整体架构。它主要由客户端和服务器端两部分组成。客户端负责用户界面和交互逻辑的展示,服务器端负责数据存储和通信管理。双方通过TCP/IP协议进行通信。 其次,我们会发现teamtalk安卓源码具有丰富的功能。用户可以注册账号、登录、添加好友、发送文字和语音消息、创建群组等。它支持即时消息的收发、离线消息的存储和推送,还提供了消息撤回和删除的功能。此外,它还支持实时语音和视频通话,可以进行多人会议。 在剖析过程中,我们还会了解其核心技术点。比如,teamtalk安卓源码使用了SQLite数据库进行数据存储,使用了音视频编解码技术来保证语音和视频通话的质量。另外,它采用了高效的网络通信协议和算法,保证了数据的安全性和实时性。 此外,我们也会注意到teamtalk安卓源码的可扩展性和开放性。它提供了丰富的接口和插件机制,允许开发者进行二次开发和定制。开发者可以根据自己的需求,添加新的功能和扩展。 总的来说,通过对teamtalk安卓源码的剖析,我们可以了解到它是一款功能强大、可扩展的即时通讯应用程序。它不仅具有各种基本的通信功能,还提供了高质量的语音和视频通话能力。对于开发者来说,通过深入研究其源码,可以获取到宝贵的经验和技术知识。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值