> For the complete documentation index, see [llms.txt](https://tarscloud.gitbook.io/tarsdocs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://tarscloud.gitbook.io/tarsdocs/ji-chu-jie-shao/tars-protocol.md).

# 基础通信协议 Tars

## 目录

> * [Tars 语言](#chapter-1)
> * [Tars 协议](#chapter-2)

## 1. Tars 语言

### 1.1. 接口文件

Tars 语言是一种类 c++标识符的语言，用于生成具体的服务接口文件

Tars 文件是 Tars 框架中客户端和服务端的通信接口，通过 Tars 的映射实现远程对象调用

Tars 文件的扩展名必须以.tars 为扩展名

对于结构定义，可以支持扩展字段，即可以增加字段而不影响原有结构的解析，可以在存储/协议等地方单独使用

大小写敏感

### 1.2. 词法规则

#### 1.2.1. 注释

采用 c++的注释规范。

```
//表示注释一行，/**/表示注释范围中的所有代码。
```

#### 1.2.2. 关键字

```
void,struct,bool,byte,short,int,double,float,long,string,vector,map,key,routekey,module,interface,out,require,optional,false,true,enum,const
```

#### 1.2.3. 标识符

所有标识符不能带有'tars\_’符号，且必须以字母开头，同时不能和关键字冲突。

### 1.3. 基本类型

支持的基本类型包括以下：

void ：只能在函数的返回值表示

bool ：布尔类型，映射到 tars::Bool

byte ：有符号字符，映射到 tars::Char

short ：有符号短整型，映射到 tars::Short

int ：有符号整型，映射到 tars::Int32

long ：有符号长整型，映射到 tars::Int64

float ：映射到 tars::Float

double ：映射到 tars::Double

string ：映射到 std::string，java:String

unsigned byte ：无符号字符,c++映射到 unsigend char 其它版本 tars::Short

unsigned short：无符号短整形 c++映射到 unsigned short 其它版本 tars::Int32

Unsigned int:无符号整形 c++映射到 unsigned int 其它版本 tars::Int64

### 1.4. 复杂类型

#### 1.4.1. 枚举

枚举类型的定义如下：

```
enum TE
{
    E1,
    E2,
    E3
};
```

说明：

> * 枚举类型支持在指定枚举变量的值，例如支持：E1 = 1 这种定义方式；

> * 第一个定义的枚举类型值为 0，这里 E1 的值为 0；

> * 枚举类型在 tars 文件定义后，通过 tars2cpp 生成以后，除了会生成相应的 enum 定义之外，会生成 etos 和 stoe 函数，将枚举值转换成字符串，以及将字符串转换成枚举值，在代码调试时会非常方便。

> * 建议在 c++的 tars 文件中，所有接口都以 int 返回，且返回值在 tars 文件中以枚举来定义。

#### 1.4.2. 常量

Tars 文件中可以定义常量，例如：

```
const int a = 0;

const string s = “abc”;
```

说明：

> * 由于 map，vector 没有描述常量的值，因此不支持 map，vector 的定义；

#### 1.4.3. 结构

结构定义如下：

```
struct Test
{
    0  require  string s;
    1  optional int  i = 23;
};

key[Test, s, i];
```

说明：

> * 第一列数字表示该字段的标识（tag），无论结构增减字段，该字段的值都不变，必须和相应的字段对应；

> * Tag 的值必须要>=0 且<=255；

> * require 表示该字段必选；

> * optional 表示该字段可选；

> * 对于 optional 字段，可以有一个缺省值，缺省值在编码时默认不打包；

key 说明：

> * 表示结构的小于比较符号，缺省时 Struct 是没有小于操作的，如果定义了 key，则生成小于比较符。

key 详细说明：

> * key\[Struct, member…]：

> * Struct：表示结构的名称

> * Member：表示该结构的成员变量，可以有多个；

> * 生成的小于比较操作符，按照 key 中成员变量定义的顺序进行优先<比较；

> * 生成小于比较操作符以后，该结构就可以作为 map 的 key；

其他说明：

> * 在 Tars 的 c++语言中，对于结构而言，提供两个成员函数用于直接打印出结构的内容，可以用于调试和记录日志：

> * ostream& display(ostream& \_os, int \_level=0)：直接打印结构的详细内容，主要用于调试；

> * ostream& displaySimple(ostream& \_os, int \_level=0)：所有成员变量自动按照顺序以|分隔打印出来，用于记录日志；

#### 1.4.4. 序列

序列用 vector 来定义，如下：

```
vector<int> vi;
```

#### 1.4.5. 字典

字典用 map 来定义，如下：

```
map<int, string> m;
```

说明：

> * 对于 struct，通常不能作为 map 的 key，因此 struct 没有大小比较符号；

> * 如果需要 struct 能够作为 map 的 key，需要用 less 定义 struct 中成员的比较顺序；

#### 1.4.7 嵌套

任何 struct，map，vector 都可以嵌套；

### 1.5. 接口

接口定义如下，例如：

```
interface Demo
{
    int get(out vector<map<int, string>> v);

    int set(vector<map<int, string>> v);
};

```

说明：

> * 表示输出参数
> * 接口定义后，通过自动代码生成工具 (如：tars2cpp)会生成同步接口和异步接口等代码

### 1.6. 名字空间

所有的 struct，interface 必须在名字空间中，例如：

```
module MemCache
{
    struct Key
    {
        0 require string s;
    };

    struct Value
    {
        0 require string s;
    };

    interface MemCacheI
    {
        int get(Key k, out Value v);

        int set(Key k, Value v);
    };
};
```

说明：

> * 名字空间不能嵌套;
> * 可以引用其他名字空间,例如:Demo1::Key

### 1.7. 引用

一个 tars 文件可以 include 另外一个 tars 文件, 只需要在头部如下引用其他文件即可: `#include "other.tars"`

即可引用其他 tars 文件中的结构体了

## 2. Tars 协议

### 2.1. 数据编码

#### 2.1.1. 基本结构

每一个数据由两个部分组成，如下图：

```
| 头信息 | 实际数据 |
```

而其中头信息包括以下几个部分：

```
| Type(4 bits) | Tag 1(4 bits) | Tag 2(1 byte) |
```

Tag 2 是可选的，当 Tag 的值不超过 14 时，只需要用 Tag 1 就可以表示；当 Tag 的值超过 14 而小于 256 时，Tag 1 固定为 15，而用 Tag 2 表示 Tag 的值。Tag 不允许大于 255。

Type 表示类型，用 4 个二进制位表示，取值范围是 0\~15，用来标识该数据的类型。不同类型的数据，其后紧跟着的实际数据的长度和格式都是不一样的，详见一下的类型表。

Tag 由 Tag 1 和 Tag 2 一起表示。取值范围是 0\~255，即该数据在结构中的字段 ID，用来区分不同的字段。

#### 2.1.2. 编码类型表

注意，这里的类型与 tars 文件定义的类型是两个不同的概念，这里的类型只是标识数据存储的类型，而不是数据定义的类型。

| 取值 | 类型         | 备注                                                              |
| -- | ---------- | --------------------------------------------------------------- |
| 0  | int1       | 紧跟 1 个字节整型数据                                                    |
| 1  | int2       | 紧跟 2 个字节整型数据                                                    |
| 2  | int4       | 紧跟 4 个字节整型数据                                                    |
| 3  | int8       | 紧跟 8 个字节整型数据                                                    |
| 4  | float      | 紧跟 4 个字节浮点型数据                                                   |
| 5  | double     | 紧跟 8 个字节浮点型数据                                                   |
| 6  | String1    | 紧跟 1 个字节长度，再跟内容                                                 |
| 7  | String4    | 紧跟 4 个字节长度，再跟内容                                                 |
| 8  | Map        | 紧跟一个整型数据表示 Map 的大小，再跟\[key, value]对列表                           |
| 9  | List       | 紧跟一个整型数据表示 List 的大小，再跟元素列表                                      |
| 10 | 自定义结构开始    | 自定义结构开始标志                                                       |
| 11 | 自定义结构结束    | 自定义结构结束标志，Tag 为 0                                               |
| 12 | 数字 0       | 表示数字 0，后面不跟数据                                                   |
| 13 | SimpleList | 简单列表（目前用在 byte 数组），紧跟一个类型字段（目前只支持 byte），紧跟一个整型数据表示长度，再跟 byte 数据 |

#### 2.1.3. 各类型详细描述

1.基本类型（包括 int1、int2、int4、int8、float、double）

头信息后紧跟数值数据。char、bool 也被看作整型。所有的整型数据之间不做区分，也就是说一个 short 的值可以赋值给一个 int。

2.数字 0

头信息后不跟数据，表示数值 0。所有基本类型的 0 值都可以这样来表示。

这是考虑到数字 0 出现的概率比较大，所以单独提一个类型，以节省空间。

3.字符串（包括 String1、String4）

String1 跟一个字节的长度（该长度数据不包括头信息），接着紧跟内容。

String4 与之类似。

4.Map

紧跟一个整形数据（包括头信息）表示 Map 的大小，然后紧跟\[Key 数据（Tag 为 0），Value 数据（Tag 为 1）]对列表。

5.List

紧跟一个整形数据（包括头信息）表示 List 的大小，然后紧跟元素列表（Tag 为 0）

6.自定义结构开始

自定义结构开始标志，后面紧跟字段数据，字段按照 tag 升序顺序排列

7.自定义结构结束

自定义结构结束标志，Tag 为 0

#### 2.1.4 对象持久化

对于自定义结构的持久化，由开始标志与结束标志来标识。

比如如下结构定义：

```
struct TestInfo
{
    1  require  int    ii  = 34;
    2  optional string s   = "abc";
};

struct TestInfo2
{
    1  require TestInfo  t;
    2  require int       a = 12345;
};

```

其中，默认的 TestInfo2 结构编码后结果为：

![tars](/files/zNNDMKyEbjnai3q8AWlE)

### 2.2. 消息格式

TUP 底层协议完全采用 Tars 定义，与 Tars 的底层数据包定义一致，其中 require 的字段为 TUP 必须的字段，optional 为访问 Tars 服务时额外需要用到的字段。

#### 2.2.1. 请求包

```
//请求包体
struct RequestPacket
{
    1  require short        iVersion;         //版本号
    2  optional byte        cPacketType;      //包类型
    3  optional int         iMessageType;     //消息类型
    4  require int          iRequestId;       //请求ID
    5  require string       sServantName;     //servant名字
    6  require string       sFuncName;        //函数名称
    7  require vector<byte> sBuffer;          //二进制buffer
    8  optional int         iTimeout;         //超时时间（毫秒）
    9  optional map<string, string> context;  //业务上下文
    10 optional map<string, string> status;   //框架协议上下文
};
```

#### 2.2.2. 响应包

```
//响应包体
struct ResponsePacket
{
    1 require short         iVersion;       //版本号
    2 optional byte         cPacketType;    //包类型
    3 require int           iRequestId;     //请求ID
    4 optional int          iMessageType;   //消息类型
    5 optional int          iRet;           //返回值
    6 require vector<byte>  sBuffer;        //二进制流
    7 optional map<string, string> status;  //协议上下文
    8 optional string       sResultDesc;    //结果描述
};

//返回值
const int TAFSERVERSUCCESS       = 0;       //服务器端处理成功
const int TAFSERVERDECODEERR     = -1;      //服务器端解码异常
const int TAFSERVERENCODEERR     = -2;      //服务器端编码异常
const int TAFSERVERNOFUNCERR     = -3;      //服务器端没有该函数
const int TAFSERVERNOSERVANTERR  = -4;      //服务器端没有该Servant对象
const int TAFSERVERRESETGRID     = -5;      //服务器端灰度状态不一致
const int TAFSERVERQUEUETIMEOUT  = -6;      //服务器队列超过限制
const int TAFASYNCCALLTIMEOUT    = -7;      //异步调用超时
const int TAFINVOKETIMEOUT       = -7;      //调用超时
const int TAFPROXYCONNECTERR     = -8;      //proxy链接异常
const int TAFSERVEROVERLOAD      = -9;      //服务器端超负载,超过队列长度
const int TAFADAPTERNULL         = -10;     //客户端选路为空，服务不存在或者所有服务down掉了
const int TAFINVOKEBYINVALIDESET = -11;     //客户端按set规则调用非法
const int TAFCLIENTDECODEERR     = -12;     //客户端解码异常
const int TAFSERVERUNKNOWNERR    = -99;     //服务器端位置异常
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://tarscloud.gitbook.io/tarsdocs/ji-chu-jie-shao/tars-protocol.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
