erlang自定义二进制协议
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

98 lines
6.3 KiB

  1. genProto
  2. =====
  3. An OTP library
  4. Build
  5. -----
  6. $ rebar compile
  7. 简单描述
  8. 之前一直想找个可用于erlang游戏或者erlang其他网络应用的协议解析编码解码的项目,且希望具有较高的编码解码性能,
  9. 大概瞄过 flatc, ecannp以及gpb(erlang protobuff)协议, 最后还是决定自己来写个,就当着写着玩吧,以后有机会
  10. 也可以用上。由于时间关系,自己只简单评测,测试编码解码性能稍微比gpb好点, 更加详细的,感兴趣可自行评测。我已经尽量
  11. 优化了编码解码的代码使其编码解码速度更快,但是实际上没达到我的预期。
  12. 开源此项目的目的是希望有人可以来review并提出优化的方法。
  13. 协议文件存放在proto目录 文件名为 Message protocol definition file的缩写 mpdf
  14. 源码目录为src,如果想要浏览解码编码的代码主要看protoCode.erl即可, 其他文件都是辅助生成协议的代码,
  15. test目录主要用于生成协议和测试的脚本以及用于测试的代码,有建议提issue,谢谢!
  16. 二进制语法
  17. Bin = <<E1, E2, ... En>>
  18. <<E1, E2, ... En>> = Bin
  19. 每个E 1..n 指定bitstring的Segment
  20. 每个段具有以下一般语法:
  21. Value:Size/TypeSpecifierList
  22. 可以省略Size或TypeSpecifier或两者。因此,允许以下变体:
  23. Ei =
  24. Value |
  25. Value:Size |
  26. Value/TypeSpecifierList |
  27. Value:Size/TypeSpecifierList
  28. Value
  29. 当在二进制构造中使用时,Value部分是任何表达式,用于求值为整数,浮点或位串,如果表达式不是单个文字或变量,则将其括在括号中。
  30. 在二进制匹配中使用时,用于位串匹配,Value必须是变量,或整数,浮点或字符串,简单而言就是Value部分必须是文字或变量。
  31. Size
  32. 在位串构造中使用,Size是要求求整数的表达式。
  33. 用于位串匹配,Size必须是整数,或绑定到整数的变量。
  34. Size的值以Unit指定段的大小,默认值取决于类型
  35. • For integer it is 8.
  36. • For float it is 64.
  37. • For binary and bitstring it is the whole binary or bit string.
  38. 在匹配中,此默认值仅对最后一个元素有效。匹配中的所有其他位串或二进制元素必须具有大小规范,段的大小Size部分乘以TypeSpecifierList中的unit(稍后描述)给出了段的位数.对于utf8,utf16和utf32类型,不得给出Size的大小。段的大小由类型和值本身隐式确定。
  39. TypeSpecifierList
  40. 是一个类型说明符列表,按任何顺序,用连字符("-")分隔。默认值用于任何省略的类型说明符
  41. Type
  42. Type= integer | float | binary | bytes | bitstring | bits | utf8 | utf16 | utf32
  43. 默认值为integer。bytes是二进制的简写,bits是bitstring的简写。有关utf类型的更多信息,请参见下文。
  44. Signedness
  45. Signedness= signed | unsigned
  46. 只有匹配和类型为整数时才有意义。默认值为无符号。
  47. Endianness
  48. Endianness= big | little | native
  49. Native-endian意味着字节顺序在加载时被解析为big-endian或little-endian,具体取决于运行Erlang机器的CPU的本机内容。仅当Type为integer,utf16,utf32或float时,字节顺序才有意义。默认值为big。
  50. Unit
  51. Unit= unit:IntegerLiteral
  52. 允许的范围是1..256。对于integer,float和bitstring,默认值为1;对于binary,默认值为8。对于utf8,utf16和utf32类型,不能给出Unit说明符。
  53. 它与Size说明符相乘,以给出段的有效大小。单位大小指定没有大小的二进制段的对齐方式,二进制类型的段必须具有可被8整除的大小
  54. 注意
  55. 构造二进制文件时,如果整数段的大小N太小而不能包含给定的整数,则整数的最高有效位将被静默丢弃,并且只有N个最低有效位被放入二进制。
  56. 例子:
  57. X:4/little-signed-integer-unit:8
  58. 该元素的总大小为4 * 8 = 32位,它包含一个小端序的有符号整数
  59. 关于 utf8 utf16 utf32
  60. 构造utf类型的段时,Value必须是0..16#D7FF或16#E000 .... 16#10FFFF范围内的整数。如果Value超出允许范围,则构造将失败并返回badarg异常。生成的二进制段的大小取决于类型或值,或两者:
  61. • For utf8, Value is encoded in 1-4 bytes.
  62. • For utf16, Value is encoded in 2 or 4 bytes.
  63. • For utf32, Value is always be encoded in 4 bytes.
  64. 构造时,可以给出一个文字字符串,后跟一个UTF类型,例如:<<“abc”/ utf8 >>,这是<< $ a / utf8,$ b / utf8,$ c / utf8的语法糖>>。
  65. 成功匹配utf类型的段,得到0..16#D7FF或16#E000..16#10FFFF范围内的整数。
  66. 如果返回值超出这些范围,则匹配失败。
  67. 如何实现二进制文件
  68. 在内部,二进制和位串以相同的方式实现。
  69. 内部有四种类型的二进制对象:
  70. 两个是二进制数据的容器,称为:
  71. • Refc binaries (short for reference-counted binaries)
  72. • Heap binaries
  73. 两个仅仅是对二进制文件的一部分的引用,被称为:
  74. • sub binaries
  75. • match contexts
  76. Refc Binaries
  77. Refc二进制文件由两部分组成:
  78. •存储在进程堆上的对象,称为ProcBin
  79. •二进制对象本身,存储在所有进程堆之外
  80. 任何数量的进程都可以通过任意数量的ProcBins引用二进制对象。该对象包含一个引用计数器,用于跟踪引用的数量,以便在最后一个引用消失时将其删除。
  81. 进程中的所有ProcBin对象都是链表的一部分,因此当ProcBin消失时,垃圾收集器可以跟踪它们并减少二进制文件中的引用计数器。
  82. Heap Binaries
  83. 堆二进制文件是小型二进制文件,最多64个字节,并直接存储在进程堆上。它们在进程被垃圾收集时以及作为消息发送时被复制。它们不需要垃圾收集器进行任何特殊处理。
  84. Sub Binaries
  85. The reference objects sub binaries and match contexts can reference part of a refc binary or heap binary
  86. 子二进制文件由split_binary / 2创建或者当二进制文件以二进制模式匹配时。子二进制是对另一个二进制文件(refc或堆二进制文件的一部分,但从不进入另一个子二进制文件)的引用。因此,匹配二进制文件相对便宜,因为实际的二进制数据永远不会被复制。
  87. Match Context
  88. 匹配上下文类似于子二进制,但针对二进制匹配进行了优化