初探Erlang的term_to_binary数据封包机制
来源:互联网 发布:绘地图软件 编辑:程序博客网 时间:2024/05/17 03:50
1、引言
erlang:term_to_binary/1,2函数返回值是Erlang扩展term格式(Erlang external term format)的binary,即ext_binary(),
这个函数能把Erlang数据封装成二进制流,是一种存储和传输Erlang数据的有效途径,
甚至可以用这种封包/解包方式用作Socket的通信协议(某页游项目就是这么干的)。
读懂Erlang扩展term格式的二进制数据,你就可以用任意语言解包Erlang数据。
直接分析二进制流,语言之间沟通无限。
2、初识Erlang的ext_binary
2.1、从简单实例说起...
Eshell V5.10.1 (abort with ^G)1> term_to_binary({}).<<131,104,0>>2> term_to_binary({1}).<<131,104,1,97,1>>3> term_to_binary({1,2}).<<131,104,2,97,1,97,2>>4> term_to_binary([]).<<131,106>>5> term_to_binary([1]).<<131,107,0,1,1>>6> term_to_binary([1,2]).<<131,107,0,2,1,2>>
2.2、从简单实例思考...
(1) 为什么第1字节都是131? (2) 为什么tuple的第2字节都是104? (3) 为什么空list第2字节是106? (4) 为什么非空list第2字节都是107? (5) ...
2.3、在C源码中找答案...
$ERL_TOP/erts/emulator/beam/external.h
$ERL_TOP/erts/emulator/beam/external.c
从函数erts_term_to_binary(Process* p, Eterm Term, int level, Uint flags)中可以看到,
首先是在第一字节压入一个版本号:
#define VERSION_MAGIC 131 /* 130 in erlang 4.2 */ /* Increment this when changing the external format. */ /* ON the other hand, don't change the external format */ /* since that breaks other people's code! *//* * Get a pointer to the binary bytes, for a heap or refc binary * (NOT sub binary). */#define binary_bytes(Bin)\ (*binary_val(Bin) == HEADER_PROC_BIN ?\ ((ProcBin *) binary_val(Bin))->bytes :\ (ASSERT_EXPR(thing_subtag(*binary_val(Bin)) == HEAP_BINARY_SUBTAG),\ (byte *)(&(((ErlHeapBin *) binary_val(Bin))->data))))bin = new_binary(p, (byte *)NULL, size);bytes = binary_bytes(bin);bytes[0] = VERSION_MAGIC;然后进入函数enc_term,来看一下enc_term中的重要片断:
switch(tag_val_def(obj)) { case NIL_DEF: // 如果是空列表,则压入NIL_EXT标识 *ep++ = NIL_EXT; break; // ......case LIST_DEF: {int is_str;i = is_external_string(obj, &is_str);if (is_str) { // 如果是字符list,则压入STRING_EXT标识 *ep++ = STRING_EXT; put_int16(i, ep); ep += 2; while (is_list(obj)) {Eterm* cons = list_val(obj);*ep++ = unsigned_val(CAR(cons));obj = CDR(cons); }} else { // 如果是list,则压入LIST_EXT标识 *ep++ = LIST_EXT; put_int32(i, ep); ep += 4; goto encode_one_cons;} } break;case TUPLE_DEF: ptr = tuple_val(obj); i = arityval(*ptr); ptr++; if (i <= 0xff) { // 如果是小tuple,则压入SMALL_TUPLE_EXT标识*ep++ = SMALL_TUPLE_EXT;put_int8(i, ep);ep += 1; } else {*ep++ = LARGE_TUPLE_EXT;put_int32(i, ep);ep += 4; } if (i > 0) {WSTACK_PUSH(s, ENC_LAST_ARRAY_ELEMENT+i-1);WSTACK_PUSH(s, (UWord) ptr); } break; // ......}从这里可以了解到,ext_binary数据封包其实就是不同的数据类型前面给予不同的标识,
这些标识究竟是怎么定义的?请结合Erlang内部数据结构,往下看...
2.4、从简单实例答疑...
/* Same order as the ordering of terms in erlang *//* Since there are 255 different External tag values to choose from There is no reason to not be extravagant. Hence, the different tags for large/small tuple e.t.c*/#ifdef ERTS_WANT_EXTERNAL_TAGS#ifndef ERTS_EXTERNAL_TAGS#define ERTS_EXTERNAL_TAGS#define SMALL_INTEGER_EXT 'a'#define INTEGER_EXT 'b'#define FLOAT_EXT 'c'#define ATOM_EXT 'd'#define SMALL_ATOM_EXT 's'#define REFERENCE_EXT 'e'#define NEW_REFERENCE_EXT 'r'#define PORT_EXT 'f'#define NEW_FLOAT_EXT 'F'#define PID_EXT 'g'#define SMALL_TUPLE_EXT 'h'#define LARGE_TUPLE_EXT 'i'#define NIL_EXT 'j'#define STRING_EXT 'k'#define LIST_EXT 'l'#define BINARY_EXT 'm'#define BIT_BINARY_EXT 'M'#define SMALL_BIG_EXT 'n'#define LARGE_BIG_EXT 'o'#define NEW_FUN_EXT 'p'#define EXPORT_EXT 'q'#define FUN_EXT 'u'#define ATOM_UTF8_EXT 'v'#define SMALL_ATOM_UTF8_EXT 'w'#define DIST_HEADER 'D'#define ATOM_CACHE_REF 'R'#define ATOM_INTERNAL_REF2 'I'#define ATOM_INTERNAL_REF3 'K'#define BINARY_INTERNAL_REF 'J'#define BIT_BINARY_INTERNAL_REF 'L'#define COMPRESSED 'P'我们先把问题中的几个ASCII码转换成对应字符:
Eshell V5.10.1 (abort with ^G)1> [104,106,107]."hjk"根据这些字符,可以从在上面找到相应的宏,现在可解答上面的问题了:
(1) 为什么第1字节都是131? 答:它是一个版本号。 (2) 为什么tuple的第2字节都是104? 答:它是一个SMALL_TUPLE_EXT标识。 (3) 为什么空list第2字节是106? 答:它是一个NIL_EXT标识,表示一个空list。 (4) 为什么非空list第2字节都是107? 答:它是一个STRING_EXT标识,表示一个字符串,在Erlang中字符串其实就是list,但list不一定是字符串。 (5) ...
3、小结
研究Erlang的ext_binary,可以从term_to_binary和binary_to_term这两个函数的内部实现入手,一层层深入,本文只是抛砖引玉,有兴趣的同学可以继续深入研究,有成果别忘了通知一声,分享分享,共同进步!
关于External Term Format,更多内容可参阅官方文档:http://www.erlang.org/doc/apps/erts/erl_ext_dist.html
PS:感谢@蓝色心情 告知关于External Term Format的官方文档链接。
- 初探Erlang的term_to_binary数据封包机制
- Erlang term_to_binary 和 binary_to_term 数据封包解包例子
- PHP扩展模块解包(由term_to_binary生成的)Erlang ext term格式的二进制数据
- mina接收数据的封包
- Erlang大量数据的存储机制:ETS和DETS
- erlang序列化工具性能对比(erlang protobuf和term_to_binary对比)
- 初探erlang的mysql数据库使用
- 拦截其它程序的网络数据封包
- 拦截其它程序的网络数据封包
- 拦截其它程序的网络数据封包
- 拦截其它程序的网络数据封包
- 拦截其它程序的网络数据封包
- 拦截其它程序的网络数据封包
- 拦截其它程序的网络数据封包
- 拦截其它程序的网络数据封包
- 拦截其它程序的网络数据封包
- [Erlang]ErlangVM的心跳机制
- erlang二进制数据垃圾回收机制
- Cocos2d-x CCNode,CCLayer,CCScene分析
- poj 2456 Aggressive cows
- 设计技巧31: 可以用接口回调,一层一层转接保护的东西
- Lync2010升级到2013之账户启用!
- 字符数组,字符指针,Sizeof总结 .
- 初探Erlang的term_to_binary数据封包机制
- 设计技巧32:信使简化代码 Messenger 简单地将信息打包到一个用于传送的对象中
- SQL Server 2008中的代码安全(五):非对称密钥加密
- SQL SERVER 带包含列的索引
- Lua学习笔记(七)
- android 自定义水平的ProgressBar
- 增加SD卡fat32文件系统的读
- Extjs4 设置panel内部的gridpanel的滚动条
- mysql和sqlserver的order by 和group by和distinct引起的兼容性问题 max函数解决