11. External Term Format
11外部术语格式
11.1引言
外部术语格式主要用于Erlang的分发机制。
由于Erlang具有固定数量的类型,因此程序员不需要为某些应用程序中使用的外部格式定义规范。所有Erlang术语都有外部表示,不同术语的解释是特定于应用程序的。
在Erlang中,BIF erlang:term_to_binary/1,2
用于将术语转换为外部格式。要将二进制数据编码转换为术语,使用BIF erlang:binary_to_term/1
。
分布在跨节点边界发送消息时会隐式执行此操作。
术语格式的整体格式如下所示:
1 | 1 | N |
---|---|---|
131 | Tag | Data |
注
当消息是passed between connected nodes
和a时distribution header
,包含版本号(131)的第一个字节在分配头后面的术语中被省略。这是因为版本号由分发标题中的版本号隐含。
压缩术语格式如下:
1 | 1 | 4 | N |
---|---|---|---|
131 | 80 | UncompressedSize | Zlib-compressedData |
未压缩大小(大端字节顺序中的无符号32位整数)是压缩前数据的大小。压缩数据展开后的格式如下:
1 | 未压缩的大小 |
---|---|
标签 | 数据 |
注
从ERTS 9.0(OTP 20)开始,原子可以包含任何Unicode字符,并且始终使用UTF-8外部格式ATOM_UTF8_EXT
或SMALL_ATOM_UTF8_EXT
。旧的Latin-1的格式ATOM_EXT
和SMALL_ATOM_EXT
已过时,对由旧的节点编码条件时仅保持向后兼容性。
从ERTS 5.10(OTP R16)开始支持外部格式的UTF-8编码原子。这种能力允许这样的旧节点解码,存储和编码从新的OTP 20节点接收到的任何Unicode原子。
一个原子中允许的最大字符数是255.在UTF-8的情况下,每个字符可能需要4个字节进行编码。
11.2分发标题
从ERTS 5.7.2开始,旧的原子缓存协议被删除,并引入了新的原子缓存协议。该协议引入了分发标题。ERTS版本早于5.7.2的节点仍然可以与新节点通信,但不使用分发头和原子高速缓存。
分发标题只包含一个原子缓存参考部分,但可以包含更多信息。分配标题在外部格式上的一个或多个Erlang术语之前。有关更多信息,请参阅文档protocol between connected nodes
中的distribution protocol
文档。
ATOM_CACHE_REFAtomCacheReferenceIndex在分发标题之后以外部格式编码的具有相应术语的条目是指在分发标题中进行的原子高速缓存引用。范围是0 <= AtomCacheReferenceIndex<255,也就是说,最多可以创建255个不同的原子高速缓存引用。
分发头格式如下:
1 | 1 | 1 | NumberOfAtomCacheRefs/2+1 | 0 | N | 0 |
---|---|---|---|---|
131 | 68 | NumberOfAtomCacheRefs | Flags | AtomCacheRefs |
Flags
由NumberOfAtomCacheRefs/2+1
字节组成,除非NumberOfAtomCacheRefs
是0
。如果NumberOfAtomCacheRefs
是0
,Flags
并且AtomCacheRefs
被省略。每个原子缓存引用都有一个半字节的标志字段。对应于特定AtomCacheReferenceIndex
的标志位于标志字节编号中AtomCacheReferenceIndex/2
。标志字节0
是字节后的第一个NumberOfAtomCacheRefs
字节。偶数的标志AtomCacheReferenceIndex
位于最低有效半字节中,而奇数标志AtomCacheReferenceIndex
位于最高有效半字节中。
原子缓存引用的标志字段具有以下格式:
1 bit | 3 bits |
---|---|
NewCacheEntryFlag | SegmentIndex |
最重要的一点是NewCacheEntryFlag
。如果设置,则相应的缓存引用是新的。三个最低有效位是SegmentIndex
相应的原子缓存条目。原子缓存由8个段组成,每个段的大小为256,即原子缓存可以包含2048个条目。
在原子高速缓存引用的标志字段之后,另一个半字节标志字段的格式如下:
3 bits | 1 bit |
---|---|
CurrentlyUnused | LongAtoms |
该半字节中的最低有效位是标志LongAtoms
。如果已设置,则2个字节用于分配标题中的原子长度而不是1个字节。
在后Flags
场跟随AtomCacheRefs
。第一个AtomCacheRef
是对应于AtomCacheReferenceIndex
0的那个。较高的索引在索引之后依次出现NumberOfAtomCacheRefs - 1
。
如果已经设置NewCacheEntryFlag
了下AtomCacheRef
一个NewAtomCacheRef
,则按照以下格式:
1 | 1 | 2 | Length |
---|---|---|
InternalSegmentIndex | Length | AtomText |
InternalSegmentIndex
以及SegmentIndex
完全识别原子缓存中原子缓存条目的位置。Length
是AtomText
包含的字节数。如果LongAtoms
已设置标志,则长度为2个字节的大端整数,否则为1个字节的整数。当分配标志DFLAG_UTF8_ATOMS
已经在两个节点之间交换时distribution handshake
,字符AtomText
以UTF-8编码,否则以Latin-1编码。下面CachedAtomRef
s的相同的SegmentIndex
和InternalSegmentIndex
,因为这NewAtomCacheRef
是指这原子直到一个新的NewAtomCacheRef
具有相同的SegmentIndex
和InternalSegmentIndex
出现。
有关原子编码的更多信息,请参阅note on UTF-8 encoded atoms
本节的开始部分。
如果NewCacheEntryFlag
在未来AtomCacheRef
还没有确定,一个CachedAtomRef
在下面的格式如下:
| 1 |
|:----|
国际分割指数
InternalSegmentIndex
以及SegmentIndex
标识原子缓存中原子缓存条目的位置。对应于该原子CachedAtomRef
是最新的NewAtomCacheRef
前述这CachedAtomRef
在另一个先前通过分配头。
11.3 atom_cache_ref
1 | 1 |
---|---|
82 | AtomCacheReferenceIndex |
指在原子AtomCacheReferenceIndex
中distribution header
。
11.4 small_integer_ext
1 | 1 |
---|---|
97 | Int |
无符号的8位整数。
11.5integer_ext
1 | 4 |
---|---|
98 | Int |
以大端格式签名的32位整数。
11.6 float_ext
1 | 31 |
---|---|
99 | 浮动字符串 |
浮点数以字符串格式存储。sprintf中用来格式化float的格式是“%.20e”(分配的字节数多于必需的)。要解压float,使用格式为“%lf”的sscanf。
此术语用于外部格式的次要版本0; 它已被取代NEW_FLOAT_EXT
。
11.7reference_ext
1 | N | 4 | 1 |
---|---|---|---|
101 | Node | ID | Creation |
编码参考对象(用于生成的对象erlang:make_ref/0
)。该Node
术语是编码原子,也就是ATOM_UTF8_EXT
,SMALL_ATOM_UTF8_EXT
或ATOM_CACHE_REF
。该ID
字段包含一个大端无符号整数,但将被视为未解释的数据
,因为该字段是特定于节点的。Creation
是一个包含节点序列号的字节,可以将旧的(崩溃的)节点与新的节点分开。
在ID
,只有18位是重要的; 其余的都是0.在中Creation
,只有两位是重要的; 其余的是0.见NEW_REFERENCE_EXT
。
11.8port_ext
1 | N | 4 | 1 |
---|---|---|---|
102 | Node | ID | Creation |
编码一个端口对象(从中获得erlang:open_port/2
)。这ID
是本地端口的节点特定标识符。跨节点边界不允许端口操作。该Creation
作品只是喜欢REFERENCE_EXT
。
11.9 pid_ext
1 | N | 4 | 4 | 1 |
---|---|---|---|---|
103 | Node | ID | Serial | Creation |
编码一个进程标识符对象(从erlang:spawn/3
或朋友获得)。在ID
和Creation
领域工作就像在REFERENCE_EXT
,而Serial
外地来提高安全性。在ID
,只有15位是重要的; 其余的都是0。
11.10small_tuple_ext
1 | 1 | N |
---|---|---|
104 | Arity | Elements |
编码一个元组。该Arity
字段是一个无符号字节,用于确定节中后续的元素数量Elements
。
11.11large_tuple_ext
1 | 4 | N |
---|---|---|
105 | Arity | Elements |
和SMALL_TUPLE_EXT
一样,除了Arity
在big-endian格式的无符号4字节整数。
11.12map_ext
1 | 4 | N |
---|---|---|
116 | Arity | Pairs |
编码地图。Arity字段是一个大端格式的无符号4字节整数,用于确定映射中键值对的数量。键和值对(Ki => Vi)Pairs按以下顺序在部分中进行编码:K1, V1, K2, V2,..., Kn, Vn。重复的键不允许在同一张地图内。
从
Erlang / OTP 17.0开始
11.13 nil_ext
| 1 |
|:----|
| 106 |
空列表的表示形式,即Erlang语法[]
。
11.14 string_ext
1 | 2 | Len |
---|---|---|
107 | Length | Characters |
串并不
具有相应的Erlang表示,但对于在分布更有效地(在0-255范围内的整数)发送字节数的列表的最优化。由于字段Length
是无符号的2字节整数(big-endian),因此实现必须确保超过65535个元素的列表被编码为LIST_EXT
。
11.15 list_ext
1 | 4 | | |
---|---|---|---|
108 | Length | Elements | Tail |
Length
是部分中后面的元素的数量Elements
。Tail
是列表的最后尾部; 它是NIL_EXT
一个适当的列表,但如果列表不正确(例如),则可以是任何类型[a|b]
。
11.16 binary_ext
1 | 4 | Len |
---|---|---|
109 | Len | Data |
二进制文件具有比特语法表达或产生的erlang:list_to_binary/1
,erlang:term_to_binary/1
或作为从二进制端口的输入。该Len
长度字段是无符号的4字节整数(大端)。
11.17 small_big_ext
1 | 1 | 1 | n |
---|---|---|---|
110 | n | Sign | d(0) ... d(n-1) |
Bignums以一个Sign
字节的一元形式存储,即,如果binum为正,则为0,如果为负,则为1。数字与首先存储的最低有效字节一起存储。要计算整数,可以使用以下公式:
B
=256
(d0*B^0 + d1*B^1 + d2*B^2 + ... d(N-1)*B^(n-1))
11.18 large_big_ext
1 | 4 | 1 | n |
---|---|---|---|
111 | n | Sign | d(0) ... d(n-1) |
和SMALL_BIG_EXT
相同,只是长度字段是无符号的4字节整数。
11.19 new_reference_ext
1 | 2 | N | 1 | N' |
---|---|---|---|---|
114 | Len | Node | Creation | ID ... |
Node
和Creation
如在REFERENCE_EXT
。
ID
包含一系列大端无符号整数(每个4字节,所以N'
是4的倍数),但被视为未解释的数据。
N'
=4%2ALen
.
在第一个字(4字节)中ID
,只有18位是有效的,其余的是0.其中Creation
,只有两位是显着的,其余的都是0。
NEW_REFERENCE_EXT
在分发版本4中引入。在版本4中,N'
最多为12。
参见REFERENCE_EXT
。
11.20 fun_ext
1 | 4 | N1 | N2 | N3 | N4 | N5 |
---|---|---|---|---|---|---|
117 | NumFree | PID | 模 | 指数 | uniq的 | 免费增值税... |
Pid
标识符作为在PID_EXT
的方法。表示乐趣创建的过程。
Module
编码为一个原子,使用ATOM_UTF8_EXT
,SMALL_ATOM_UTF8_EXT
或ATOM_CACHE_REF
。这是有趣的模块。
Index
用SMALL_INTEGER_EXT
or 编码的整数INTEGER_EXT
。它通常是模块有趣表中的一个小索引。
Uniq
用SMALL_INTEGER_EXT
or 编码的整数INTEGER_EXT
。Uniq
是乐趣的解析的哈希值。
Free vars
NumFree
术语数量,每一个都根据其类型编码。
11.21 new_fun_ext
1 | 4 | 1 | 16 | 4 | 4 | N1 | N2 | N3 | N4 | N5 |
---|---|---|---|---|---|---|---|---|---|---|
112 | Size | Arity | Uniq | Index | NumFree | Module | OldIndex | OldUniq | Pid | Free Vars |
这是内部乐队的新编码:fun F/A和fun(Arg1,..) -> ... end。
Size
总字节数,包括字段Size
。
Arity
实现乐趣的功能。
Uniq
Beam文件重要部分的16字节MD5。
Index
索引编号。模块中的每个乐趣都有一个唯一的索引。Index
以大端字节顺序存储。
NumFree
自由变量的数量。
Module
编码为一个原子,使用ATOM_UTF8_EXT
,SMALL_ATOM_UTF8_EXT
或ATOM_CACHE_REF
。该乐趣是在哪个模块中实现的。
OldIndex
用SMALL_INTEGER_EXT
or 编码的整数INTEGER_EXT
。通常是模块有趣表中的一个小索引。
OldUniq
用SMALL_INTEGER_EXT
or 编码的整数INTEGER_EXT
。Uniq
是乐趣的分析树的哈希值。
Pid
标识符作为在PID_EXT
的方法。表示乐趣创建的过程。
Free vars
NumFree
术语数量,每一个都根据其类型编码。
11.22 export_ext
1 | N1 | N2 | N3 |
---|---|---|---|
113 | Module | Function | Arity |
这个术语是外部乐趣的编码:fun M:F/A
。
Module
和Function
是原子(使用编码ATOM_UTF8_EXT
,SMALL_ATOM_UTF8_EXT
或ATOM_CACHE_REF
)。
Arity
是使用编码的整数SMALL_INTEGER_EXT
。
11.23 bit_binary_ext
1 | 4 | 1 | Len |
---|---|---|---|
77 | Len | Bits | Data |
这个术语表示一个比特串,其比特长度不一定是8的倍数。该Len
字段是一个无符号的4字节整数(大端)。该Bits
字段是在数据字段的最后一个字节中使用的位数(1-8),从最高有效位到最低有效位计数。
11.24 new_float_ext
1 | 8 |
---|---|
70 | IEEE float |
浮点数以8字节存储为big-endian IEEE格式。
该术语用于外部格式的次要版本1。
11.25 atom_utf8_ext
1 | 2 | Len |
---|---|---|
118 | Len | AtomName |
一个原子以大端顺序存储一个2字节的无符号长度,接着是Len
包含AtomName
以UTF-8编码的字节。
有关原子编码的更多信息,请参阅note on UTF-8 encoded atoms
本节的开始部分。
11.26 small_atom_utf8_ext
1 | 1 | Len |
---|---|---|
119 | Len | AtomName |
一个原子以1字节的无符号长度存储,随后是Len
包含AtomName
以UTF-8编码的字节。用UTF-8编码的更长的原子可以用来表示ATOM_UTF8_EXT
。
有关原子编码的更多信息,请参阅note on UTF-8 encoded atoms
本节的开始部分。
11.27 ATOM_EXT (deprecated)
1 | 2 | Len |
---|---|---|
100 | Len | AtomName |
一个原子以大端顺序存储2个字节的无符号长度,然后Len
是8位拉丁-1字符的数字组成AtomName
。最大允许值为Len
255。
11.28 SMALL_ATOM_EXT (deprecated)
1 | 1 | Len |
---|---|---|
115 | Len | AtomName |
原子以1字节的无符号长度存储,接着Len
是8位拉丁-1字符的数字组成AtomName
。
注
SMALL_ATOM_EXT
在ERTS 5.7.2介绍并要求分布标志的交流DFLAG_SMALL_ATOM_TAGS
中distribution handshake
。