淺析Hessian協議
Hessian二進制的網絡協議使不需要引入大型框架下就可以使用,並且不需要學習其它的入門的協議。因爲它是二進制協議,它更擅長於發送二進制數據,而不需要引入其它附件去擴展它的協議。
Hessian支持很多種語言,例如Java,Flash/Flex,python,c++,.net/c#,D,Erlang,PHP,Ruby,Object C等
下面我們就一起閱讀一下Hessian2.0的文檔:https://link.jianshu.com?t=http://hessian.caucho.com/doc/hessian-serialization.html
介紹
Hessian是一個動態類型,二進制序列化,也是網絡協議爲了對象的定向傳輸。
設計目標
Hessian是一個動態類型,簡潔的,可以移植到各個語言
Hessian協議有以下的設計目標:
- 它必須自我描述序列化的類型,即不需要外部架構和接口定義
- 它必須是語言語言獨立的,要支持包括腳本語言
- 它必須是可讀可寫的在單一的途徑
- 它要儘可能的簡潔
- 它必須是簡單的,它可以有效地測試和實施
- 儘可能的快
- 必須要支持Unicode編碼
- 它必須支持八位二進制文件,而不是逃避或者用附件
- 它必須支持加密,壓縮,簽名,還有事務的上下文
Hessian語法
序列化語法:
# starting production
top ::= value
# 8-bit binary data split into 64k chunks
binary ::= x41 b1 b0 <binary-data> binary # non-final chunk
::= 'B' b1 b0 <binary-data> # final chunk
::= [x20-x2f] <binary-data> # binary data of
# length 0-15
::= [x34-x37] <binary-data> # binary data of
# length 0-1023
# boolean true/false
boolean ::= 'T'
::= 'F'
# definition for an object (compact map)
class-def ::= 'C' string int string*
# time in UTC encoded as 64-bit long milliseconds since
# epoch
date ::= x4a b7 b6 b5 b4 b3 b2 b1 b0
::= x4b b3 b2 b1 b0 # minutes since epoch
# 64-bit IEEE double
double ::= 'D' b7 b6 b5 b4 b3 b2 b1 b0
::= x5b # 0.0
::= x5c # 1.0
::= x5d b0 # byte cast to double
# (-128.0 to 127.0)
::= x5e b1 b0 # short cast to double
::= x5f b3 b2 b1 b0 # 32-bit float cast to double
# 32-bit signed integer
int ::= 'I' b3 b2 b1 b0
::= [x80-xbf] # -x10 to x3f
::= [xc0-xcf] b0 # -x800 to x7ff
::= [xd0-xd7] b1 b0 # -x40000 to x3ffff
# list/vector
list ::= x55 type value* 'Z' # variable-length list
::= 'V' type int value* # fixed-length list
::= x57 value* 'Z' # variable-length untyped list
::= x58 int value* # fixed-length untyped list
::= [x70-77] type value* # fixed-length typed list
::= [x78-7f] value* # fixed-length untyped list
# 64-bit signed long integer
long ::= 'L' b7 b6 b5 b4 b3 b2 b1 b0
::= [xd8-xef] # -x08 to x0f
::= [xf0-xff] b0 # -x800 to x7ff
::= [x38-x3f] b1 b0 # -x40000 to x3ffff
::= x59 b3 b2 b1 b0 # 32-bit integer cast to long
# map/object
map ::= 'M' type (value value)* 'Z' # key, value map pairs
::= 'H' (value value)* 'Z' # untyped key, value
# null value
null ::= 'N'
# Object instance
object ::= 'O' int value*
::= [x60-x6f] value*
# value reference (e.g. circular trees and graphs)
ref ::= x51 int # reference to nth map/list/object
# UTF-8 encoded character string split into 64k chunks
string ::= x52 b1 b0 <utf8-data> string # non-final chunk
::= 'S' b1 b0 <utf8-data> # string of length
# 0-65535
::= [x00-x1f] <utf8-data> # string of length
# 0-31
::= [x30-x34] <utf8-data> # string of length
# 0-1023
# map/list types for OO languages
type ::= string # type name
::= int # type reference
# main production
value ::= null
::= binary
::= boolean
::= class-def value
::= date
::= double
::= int
::= list
::= long
::= map
::= object
::= ref
::= string
Serialization
Hessian的對象有八種原始類型:
- 原生二進制數據
- Boolean
- 64位毫秒值的日期
- 64位double
- 32位int
- 64位long
- null
- utf-8的string
它有三種循環的類型:
- list for lists and arrays
- map for maps and dictionaries
- object for objects
最後,他有一種特殊組成:
- 共享和循環對象引用
Hessian 2.0 有三種內置的map:
- 一個object/list參考的map
- 一個類參考定義的map
- 一個類參考的map
4.1 二進制數據
binary ::= b b1 b0 <binary-data> binary
::= B b1 b0 <binary-data>
::= [x20-x2f] <binary-data>
二進制數據被編碼成二進制編碼塊,'B'代表最後一塊,'b'代表任編碼塊非最後一塊的部分,每一個編碼塊有16 bit的長度。
len = 256 * b1 + b0
4.1.1 可壓縮:短的二進制
Binary data with length less than 15 may be encoded by a single octet length [x20-x2f].
len = code - 0x20
當二進制數據少於15的時候,可以用一個字節將他們編碼。
4.1.2 Binary Examples
x20 # zero-length binary data
x23 x01 x02 x03 # 3 octet data
B x10 x00 .... # 4k final chunk of data
b x04 x00 .... # 1k non-final chunk of data
4.2 boolean
boolean ::= T
::= F
The octet 'F' represents false and the octet T represents true.
4.3 日期
時間編碼:
date ::= x4a b7 b6 b5 b4 b3 b2 b1 b0
::= x4b b4 b3 b2 b1 b0
Date represented by a 64-bit long of milliseconds since Jan 1 1970 00:00H, UTC.
4.3.1 時間用分鐘表示
The second form contains a 32-bit int of minutes since Jan 1 1970 00:00H, UTC.
4.3.2 日期例子
x4a x00 x00 x00 xd0 x4b x92 x84 xb8 # 09:51:31 May 8, 1998 UTC
x4b x4b x92 x0b xa0 # 09:51:00 May 8, 1998 UTC
4.4 double
double算法
double ::= D b7 b6 b5 b4 b3 b2 b1 b0
::= x5b
::= x5c
::= x5d b0
::= x5e b1 b0
::= x5f b3 b2 b1 b0
4.4.1 緊湊的二進制的0
可以用x5b代替double的0.0
4.4.2 緊湊的二進制的1
可以用x5c代替double的1.0
4.4.3 double 的八位字節
double 介於-128到127之間的無符號的可以用兩個byte value來替代。
value = (double)b0
4.4.4
double 介於-32768和32767之間無符號的double,可以用三個八位字節來替代。
value = (double) (256 * b1 + b0)
4.4.5
32位浮點數可以轉換成4位8字節二進制數
4.4.6 double例子
x5b # 0.0
x5c # 1.0
x5d x00 # 0.0
x5d x80 # -128.0
x5d x7f # 127.0
x5e x00 x00 # 0.0
x5e x80 x00 # -32768.0
x5e x7f xff # 32767.0
D x40 x28 x80 x00 x00 x00 x00 x00 # 12.25
4.5 int
int ::= 'I' b3 b2 b1 b0
::= [x80-xbf]
::= [xc0-xcf] b0
::= [xd0-xd7] b1 b0
一個32bit有符號整數,一個整數以'I'開頭,後面跟着4個八個字節.
value = (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
4.5.1 單一的八字節數字
數字介於-16至47之間的可以被編碼成一個單獨在x80到xbf之間。
value = code - 0x90
4.5.2 兩個八字節的數字
數字介於 -2048至2047,可以被編碼成,兩個八字節字符,規則是:
value = ((code - 0xc8) << 8) + b0;
4.5.4 用三個八位字節可以表示
Integers between -262144 and 262143 can be encoded in three bytes with the leading byte in the range xd0 to xd7.
value = ((code - 0xd4) << 16) + (b1 << 8) + b0;
4.5.4 Integer Examplses
x90 # 0
x80 # -16
xbf # 47
xc8 x00 # 0
xc0 x00 # -2048
xc7 x00 # -256
xcf xff # 2047
xd4 x00 x00 # 0
xd0 x00 x00 # -262144
xd7 xff xff # 262143
I x00 x00 x00 x00 # 0
I x00 x00 x01 x2c # 300
4.6 list
list 語法
list ::= x55 type value* 'Z' # variable-length list
::= 'V' type int value* # fixed-length list
::= x57 value* 'Z' # variable-length untyped list
::= x58 int value* # fixed-length untyped list
::= [x70-77] type value* # fixed-length typed list
::= [x78-7f] value* # fixed-length untyped list
一個整齊的list,例如array。這兩個list提供一個固定長度和可編長度的list,兩個list都有一個類型,這個類型的String必須是一個可以被UTF-8支持的。
每個列表項都添加到引用列表中,以處理共享和循環元素。參見REF元素。
任何希望列表的解析器也必須接受null或共享引用。
類型的有效值沒有在本文檔中指定,並可能取決於特定的應用程序。例如,在靜態類型的語言中實現的一個服務器,它公開了一個Hessian接口,它可以使用類型信息實例化特定的數組類型。另一方面,服務器用動態類型的語言可能會忽視型完全的內容並創建一個通用陣列。
4.6.1 確定長度的list
Hesssian 2.0 允許一個緊湊的形式列表的連續列表相同的類型,其中的長度是事先已知的。類型和長度由整數編碼,其中類型是對較早指定類型的引用。
4.6.2 List示例
序列化一個int類型的數組,int[] = {0, 1}
V # fixed length, typed list
x04 [int # encoding of int[] type
x92 # length = 2
x90 # integer 0
x91 # integer 1
沒有類型長度可變的列表 list={0,1}
x57 # variable-length, untyped
x90 # integer 0
x91 # integer 1
Z
定長類型
x72 # typed list length=2
x04 [int # type for int[] (save as type #0)
x90 # integer 0
x91 # integer 1
x73 # typed list length = 3
x90 # type reference to int[] (integer #0)
x92 # integer 2
x93 # integer 3
x94 # integer 4
4.7 long
long 語法
long ::= L b7 b6 b5 b4 b3 b2 b1 b0
::= [xd8-xef]
::= [xf0-xff] b0
::= [x38-x3f] b1 b0
::= x4c b3 b2 b1 b0
64位有符號整數。一個長的字節x4c代表(L)隨後在後面跟着八個比特。
4.7.1 一位八比特能表示的數
long在-8至15是被一個八位比特替代的,在範圍xd8至xef。
value = (code - 0xe0)
4.7.2 兩位八比特能表示的long
long在-2048值2047之間,使用兩位byte保存,在範圍xf0至xff
value = ((code - 0xf8) << 8 ) + b0
4.7.3
三位八比特能表示的數,範圍在-262144至262143
value = ((code - 0x3c) << 16) + (b1 << 8) + b0
4.7.4
long能用32bite表示的數
value = (b3 << 24) + (b2 << 16) + (b1 << 8) + b0
long例子
xe0 # 0
xd8 # -8
xef # 15
xf8 x00 # 0
xf0 x00 # -2048
xf7 x00 # -256
xff xff # 2047
x3c x00 x00 # 0
x38 x00 x00 # -262144
x3f xff xff # 262143
x4c x00 x00 x00 x00 # 0
x4c x00 x00 x01 x2c # 300
L x00 x00 x00 x00 x00 x00 x01 x2c # 300
4.8
Map語法
map ::= M type (value value)* Z
表示序列化的映射,並表示對象。類型元素描述映射的類型。
這個類型可能爲空,一個長度爲0,程序解釋器會自動選擇一個類型,如果一個值是沒有類型的,對於對象,一個未確認的key將會被忽略。
每一個映射被添加到參考列表中,一些時間,語法解析程序期望一個映射,它必須支持空或者引用,這個類型被服務器選擇。
4.8.1 Map的例子
map = new HashMap();
map.put(new Integer(1), "fee");
map.put(new Integer(16), "fie");
map.put(new Integer(256), "foe");
---
H # untyped map (HashMap for Java)
x91 # 1
x03 fee # "fee"
xa0 # 16
x03 fie # "fie"
xc9 x00 # 256
x03 foe # "foe"
Z
集合表示一個java對象
public class Car implements Serializable {
String color = "aquamarine";
String model = "Beetle";
int mileage = 65536;
}
---
M
x13 com.caucho.test.Car # type
x05 color # color field
x0a aquamarine
x05 model # model field
x06 Beetle
x07 mileage # mileage field
I x00 x01 x00 x00
Z
4.9 null
null語法
null代表一個空指針
'N'代表空的值
4.10 object
object 語法
class-def ::= 'C' string int string*
object ::= 'O' int value*
::= [x60-x6f] value*
4.10.1 類定義
Hessian2.0有一個緊湊的對象,字段只會序列化一次,以下對象只會序列化它們的值。
對象定義包括強制類型字符串、字段數和字段名。對象定義存儲在對象定義映射中,並且將由具有整數引用的對象實例引用。
4.10.2 對象實例
Hessian2.0有一個緊湊的對象,字段只會序列化一次,以下對象只會序列化它們的值。
對象實例化根據前面的定義創建一個新對象。整數值是指對象定義。
4.10.3 對象示例
對象序列化
class Car {
String color;
String model;
}
out.writeObject(new Car("red", "corvette"));
out.writeObject(new Car("green", "civic"));
---
C # object definition (#0)
x0b example.Car # type is example.Car
x92 # two fields
x05 color # color field name
x05 model # model field name
O # object def (long form)
x90 # object definition #0
x03 red # color field value
x08 corvette # model field value
x60 # object def #0 (short form)
x05 green # color field value
x05 civic # model field value
enum Color {
RED,
GREEN,
BLUE,
}
out.writeObject(Color.RED);
out.writeObject(Color.GREEN);
out.writeObject(Color.BLUE);
out.writeObject(Color.GREEN);
---
C # class definition #0
x0b example.Color # type is example.Color
x91 # one field
x04 name # enumeration field is "name"
x60 # object #0 (class def #0)
x03 RED # RED value
x60 # object #1 (class def #0)
x90 # object definition ref #0
x05 GREEN # GREEN value
x60 # object #2 (class def #0)
x04 BLUE # BLUE value
x51 x91 # object ref #1, i.e. Color.GREEN
4.11 ref
Ref 語法
ref ::= x51 int
指上一個列表、映射或對象實例的整數。當每個列表、映射或對象從輸入流中讀取時,它被分配到流中的整數位置,即第一個列表或映射是“0”,下一個是“1”,等等,後面的引用可以使用前面的對象。作者可以生成參考文獻。解析器必須能夠識別它們。
REF可以引用不完全讀項。例如,在整個列表被讀取之前,循環鏈表將引用第一個鏈接。
一個可能的實現是將每個映射、列表和對象添加到數組中,因爲它是被讀取的。REF將從數組返回相應的值。爲了支持循環結構,在填充內容之前,實現將立即存儲映射、列表或對象。
每個映射或列表在解析時存儲在數組中。REF選擇一個存儲的對象。第一個對象編號爲“0”。
4.11.1 Ref 例子
list = new LinkedList();
list.data = 1;
list.tail = list;
---
C
x0a LinkedList
x92
x04 head
x04 tail
o x90 # object stores ref #0
x91 # data = 1
x51 x90 # next field refers to itself, i.e. ref #0
ref僅涉及到list,map和object。
4.12 string
string 語法
string ::= x52 b1 b0 <utf8-data> string
::= S b1 b0 <utf8-data>
::= [x00-x1f] <utf8-data>
::= [x30-x33] b0 <utf8-data>
一個16比特,利用utf-8的雙字節編碼,字符串會按塊編碼,非最後一塊會用'R'來表示,最後一塊會用'S'來表示,每一塊都有一個16比特無符號整型長度的bytes。
16比特字符的長度,可能與字節的個數不相同。
字符串可能不能成對拆分。
4.12.1 短字符串
長度小於32的字符串可能使用單字節編碼。
value = code;
4.12.2 String 例子
x00 # "", empty string
x05 hello # "hello"
x01 xc3 x83 # "\u00c3"
S x00 x05 hello # "hello" in long form
x52 x00 x07 hello, # "hello, world" split into two chunks
x05 world
4.12 type
type 語法
type ::= string
::= int
一個map或者list包含的屬性,這個屬性的屬性名將會被標示,用在面向對象的語言中。每一個類型都會被添加到type map中,給未來提供一個參考。
4.14 類型參考
重複類型的String的key,將會用type map來查詢先前用過的類型,在解析過程中,這個類型應該是不依賴於任何類型的。
Bytecode map
x00 - x1f # utf-8 string length 0-32
x20 - x2f # binary data length 0-16
x30 - x33 # utf-8 string length 0-1023
x34 - x37 # binary data length 0-1023
x38 - x3f # three-octet compact long (-x40000 to x3ffff)
x40 # reserved (expansion/escape)
x41 # 8-bit binary data non-final chunk ('A')
x42 # 8-bit binary data final chunk ('B')
x43 # object type definition ('C')
x44 # 64-bit IEEE encoded double ('D')
x45 # reserved
x46 # boolean false ('F')
x47 # reserved
x48 # untyped map ('H')
x49 # 32-bit signed integer ('I')
x4a # 64-bit UTC millisecond date
x4b # 32-bit UTC minute date
x4c # 64-bit signed long integer ('L')
x4d # map with type ('M')
x4e # null ('N')
x4f # object instance ('O')
x50 # reserved
x51 # reference to map/list/object - integer ('Q')
x52 # utf-8 string non-final chunk ('R')
x53 # utf-8 string final chunk ('S')
x54 # boolean true ('T')
x55 # variable-length list/vector ('U')
x56 # fixed-length list/vector ('V')
x57 # variable-length untyped list/vector ('W')
x58 # fixed-length untyped list/vector ('X')
x59 # long encoded as 32-bit int ('Y')
x5a # list/map terminator ('Z')
x5b # double 0.0
x5c # double 1.0
x5d # double represented as byte (-128.0 to 127.0)
x5e # double represented as short (-32768.0 to 327676.0)
x5f # double represented as float
x60 - x6f # object with direct type
x70 - x77 # fixed list with direct length
x78 - x7f # fixed untyped list with direct length
x80 - xbf # one-octet compact int (-x10 to x3f, x90 is 0)
xc0 - xcf # two-octet compact int (-x800 to x7ff)
xd0 - xd7 # three-octet compact int (-x40000 to x3ffff)
xd8 - xef # one-octet compact long (-x8 to xf, xe0 is 0)
xf0 - xff # two-octet compact long (-x800 to x7ff, xf8 is 0)