背景

股票行情一般传输的数据类型为: int / long / float /double / string 来表示行情价格成交量之类的数据。

正常传输过程中,都是使用tag=value的方式。 如1=date(标号1代表日期) 2=openPrice(2表示开盘价格) 等等, 在解析每个字段之前需要先解析这个字段标号,然后通过这个标号能够从提前约定的字段(一般编码端和解码端都有一个xml模板类似的约定配置文件)对应类型来解析这个字段。

前提约定:

tag : 1->日期 2->时间 3->开盘价 4->最高价 5->最低价 6->当前价。 其中tag为short类型,即2个字节

日期、时间为int; 开高低收为float ,保留3位小数

样例数据:

1=20190310 , 2=142900 , 3=13.4 , 4=15.0 ,5=13.0 ,6=13.5

不使用fast协议来传输需要的字节数: tag占用字节(6*2) + value(4 + 4 + 4 +4 + 4 + 4)=36字节

同样的数据,如果使用fast协议传输需要字节数: tag(6*1) +value(4 + 3 + 3+ 3+ 3)=29字节

fast协议特征

基本特征:

  1. 每个字段中所有的byte的最高位用0表示当前字节属于该字段,用1表示这是该字段的最后一个字节(停止位特征),byte流和unicode字符串流数据部分不使用停止位特征
  2. fast协议传输过程中不会传输float/double类型的数据,而是将其根据小数位【具体每个字段小数位数在模板配置文件中约定】扩展成数字类型。
  3. 数字类型在传输过程中,可以为1,2,3,4,5,6,7,8,9,10个字节,具体要根据是否为有符号、无符号、以及数字的范围来具体确定占用几个字节
  4. 在传输数字时,如果涉及到有符号数的时候,第一个字节的第2位用来表示符号,0表示正数,1表示负数。
  5. 在传输ascii编码类型的时候,占用1个字节。ascii编码本身第一位为0,,所以一个字节是符合fast协议规定的。
  6. 在传输unicode编码类型的时候,使用(size,真正数据)来传输,size代表数据真正占用的字节数。
  7. 在传输byte流的时候,和unicode编码一样,也使用(size,真正数据)来传输。
  8. 在传输unicode 和byte流的时候不使用停止位特征,即每个字节的最高位为真实数据。数据长度字段仍然使用停止位特征

下面代码出自:openfast-1.1.1

fast协议解读

停止位

org.openfast.template.type.codec

  1. /**
  2. * 数据编码成功后,将最后一个字节的首位设置成1,即为停止位
  3. *
  4. * */
  5. public byte[] encode(ScalarValue value) {
  6. byte[] encoding = encodeValue(value);
  7. encoding[encoding.length - 1] |= 0x80;
  8. return encoding;
  9. }

有符号数编码类

类:org.openfast.template.type.codec.SignedInteger

  1. /**
  2. * 编码方法
  3. * */
  4. public byte[] encodeValue(ScalarValue value) {
  5. long longValue = ((NumericValue) value).toLong();
  6. int size = getSignedIntegerSize(longValue);
  7. byte[] encoding = new byte[size];
  8. //组装数据,即每个字节第一位不表示数据;组装完成后仍然是大端序列(低字节位为值得高有效位)
  9. for (int factor = 0; factor < size; factor++) {
  10. //0x3f = 0011 1111
  11. //0x7f = 0111 1111
  12. int bitMask = (factor == (size - 1)) ? 0x3f : 0x7f;
  13. encoding[size - factor - 1] = (byte) ((longValue >> (factor * 7)) & bitMask);
  14. }
  15. // Get the sign bit from the long value and set it on the first byte
  16. // 01000000 00000000 ... 00000000
  17. // ^----SIGN BIT
  18. //将第一个字节的第二位设置为符号位, 0表示正数;1表示负数
  19. encoding[0] |= (0x40 & (longValue >> 57));
  20. return encoding;
  21. }
  22. /**
  23. * 解码方法
  24. * */
  25. public ScalarValue decode(InputStream in) {
  26. long value = 0;
  27. try {
  28. // IO read方法如果返回小于-1的时候,表示结束;正常范围0-255
  29. int byt = in.read();
  30. if (byt < 0) {
  31. Global.handleError(FastConstants.END_OF_STREAM, "The end of the input stream has been reached.");
  32. return null; // short circuit if global error handler does not throw exception
  33. }
  34. //通过首字节的第二位与运算,确认该数据的符号
  35. if ((byt & 0x40) > 0) {
  36. value = -1;
  37. }
  38. //到此,value的符号已经确定,
  39. //value=0 则该数为负数, value= -1该数为正数
  40. // int value = -1 16进制为 0xFF FF FF FF
  41. // int value = 0 16进制为 0x00 00 00 00
  42. //下面的只是通过位操作来复原真实的数据
  43. value = (value << 7) | (byt & 0x7f); //(value << 7)确保最后7位为0; (byt & 0x7f) 还是byt
  44. while ((byt & 0x80) == 0) { //根据第一位来判断当前byte是否属于这个字段
  45. byt = in.read();
  46. if (byt < 0) {
  47. Global.handleError(FastConstants.END_OF_STREAM, "The end of the input stream has been reached.");
  48. return null; // short circuit if global error handler does not throw exception
  49. }
  50. value = (value << 7) | (byt & 0x7f); //先把有效位往左移7位,然后再处理当前的七位
  51. }
  52. } catch (IOException e) {
  53. Global.handleError(FastConstants.IO_ERROR, "A IO error has been encountered while decoding.", e);
  54. return null; // short circuit if global error handler does not throw exception
  55. }
  56. return createValue(value);
  57. }
  58. /**
  59. * 判断无符号数所要占用的字节数
  60. * */
  61. public static int getUnsignedIntegerSize(long value) {
  62. if (value < 128) {
  63. return 1; // 2 ^ 7
  64. }
  65. if (value <= 16384) {
  66. return 2; // 2 ^ 14
  67. }
  68. if (value <= 2097152) {
  69. return 3; // 2 ^ 21
  70. }
  71. if (value <= 268435456) {
  72. return 4; // 2 ^ 28
  73. }
  74. if (value <= 34359738368L) {
  75. return 5; // 2 ^ 35
  76. }
  77. if (value <= 4398046511104L) {
  78. return 6; // 2 ^ 42
  79. }
  80. if (value <= 562949953421312L) {
  81. return 7; // 2 ^ 49
  82. }
  83. if (value <= 72057594037927936L) {
  84. return 8; // 2 ^ 56
  85. }
  86. return 9;
  87. }
  88. /**
  89. * 判断有符号数需要占用的字节
  90. * */
  91. public static int getSignedIntegerSize(long value) {
  92. if ((value >= -64) && (value <= 63)) {
  93. return 1; // - 2 ^ 6 ... 2 ^ 6 -1
  94. }
  95. if ((value >= -8192) && (value <= 8191)) {
  96. return 2; // - 2 ^ 13 ... 2 ^ 13 -1
  97. }
  98. if ((value >= -1048576) && (value <= 1048575)) {
  99. return 3; // - 2 ^ 20 ... 2 ^ 20 -1
  100. }
  101. if ((value >= -134217728) && (value <= 134217727)) {
  102. return 4; // - 2 ^ 27 ... 2 ^ 27 -1
  103. }
  104. if ((value >= -17179869184L) && (value <= 17179869183L)) {
  105. return 5; // - 2 ^ 34 ... 2 ^ 34 -1
  106. }
  107. if ((value >= -2199023255552L) && (value <= 2199023255551L)) {
  108. return 6; // - 2 ^ 41 ... 2 ^ 41 -1
  109. }
  110. if ((value >= -281474976710656L) && (value <= 281474976710655L)) {
  111. return 7; // - 2 ^ 48 ... 2 ^ 48 -1
  112. }
  113. if ((value >= -36028797018963968L) && (value <= 36028797018963967L)) {
  114. return 8; // - 2 ^ 55 ... 2 ^ 55 -1
  115. }
  116. if ((value >= -4611686018427387904L && value <= 4611686018427387903L)) {
  117. return 9;
  118. }
  119. return 10;
  120. }

无符号数编码类

org.openfast.template.type.codec.UnsignedInteger


  1. /**
  2. * 编码方法
  3. * */
  4. public byte[] encodeValue(ScalarValue scalarValue) {
  5. long value = scalarValue.toLong();
  6. int size = getUnsignedIntegerSize(value);
  7. byte[] encoded = new byte[size];
  8. for (int factor = 0; factor < size; factor++) {
  9. encoded[size - factor - 1] = (byte) ((value >> (factor * 7)) & 0x7f);
  10. }
  11. return encoded;
  12. }
  13. /**
  14. *
  15. * 解码方法
  16. * */
  17. public ScalarValue decode(InputStream in) {
  18. long value = 0;
  19. int byt;
  20. try {
  21. do {
  22. byt = in.read();
  23. if (byt < 0) {
  24. Global.handleError(FastConstants.END_OF_STREAM, "The end of the input stream has been reached.");
  25. return null; // short circuit if global error handler does not throw exception
  26. }
  27. value = (value << 7) | (byt & 0x7f);
  28. } while ((byt & 0x80) == 0);
  29. } catch (IOException e) {
  30. Global.handleError(FastConstants.IO_ERROR, "A IO error has been encountered while decoding.", e);
  31. return null; // short circuit if global error handler does not throw exception
  32. }
  33. return createValue(value);
  34. }

AsciiString编码类

org.openfast.template.type.codec.AsciiString


  1. public byte[] encodeValue(ScalarValue value) {
  2. if ((value == null) || value.isNull()) {
  3. throw new IllegalStateException("Only nullable strings can represent null values.");
  4. }
  5. String string = value.toString();
  6. if ((string != null) && (string.length() == 0)) {
  7. return TypeCodec.NULL_VALUE_ENCODING;
  8. }
  9. if (string.startsWith(ZERO_TERMINATOR)) {
  10. return ZERO_PREAMBLE;
  11. }
  12. return string.getBytes();
  13. }
  14. public ScalarValue decode(InputStream in) {
  15. int byt;
  16. ByteArrayOutputStream buffer = Global.getBuffer();
  17. try {
  18. do {
  19. byt = in.read();
  20. if (byt < 0) {
  21. Global.handleError(FastConstants.END_OF_STREAM, "The end of the input stream has been reached.");
  22. return null; // short circuit if global error handler does not throw exception
  23. }
  24. buffer.write(byt);
  25. } while ((byt & 0x80) == 0);
  26. } catch (IOException e) {
  27. Global.handleError(FastConstants.IO_ERROR, "A IO error has been encountered while decoding.", e);
  28. return null; // short circuit if global error handler does not throw exception
  29. }
  30. byte[] bytes = buffer.toByteArray();
  31. //复原最后一个字节为真实数据
  32. bytes[bytes.length - 1] &= 0x7f;
  33. if (bytes[0] == 0) {
  34. if (!ByteUtil.isEmpty(bytes))
  35. Global.handleError(FastConstants.R9_STRING_OVERLONG, null);
  36. if (bytes.length > 1 && bytes[1] == 0)
  37. return new StringValue("\u0000");
  38. return new StringValue("");
  39. }
  40. return new StringValue(new String(bytes));
  41. }

字节流编码类

org.openfast.template.type.codec.ByteVectorType

注意:字节流类型不使用停止位


  1. public byte[] encode(ScalarValue value) {
  2. byte[] bytes = value.getBytes();
  3. int lengthSize = IntegerCodec.getUnsignedIntegerSize(bytes.length);
  4. byte[] encoding = new byte[bytes.length + lengthSize];
  5. byte[] length = TypeCodec.UINT.encode(new IntegerValue(bytes.length));
  6. //数据流所占长度
  7. System.arraycopy(length, 0, encoding, 0, lengthSize);
  8. //数据
  9. System.arraycopy(bytes, 0, encoding, lengthSize, bytes.length);
  10. return encoding;
  11. }
  12. public ScalarValue decode(InputStream in) {
  13. //解析字节流的长度
  14. int length = ((IntegerValue) TypeCodec.UINT.decode(in)).value;
  15. byte[] encoding = new byte[length];
  16. //读取字节流
  17. for (int i = 0; i < length; i++)
  18. try {
  19. int nextByte = in.read();
  20. if (nextByte < 0) {
  21. Global.handleError(FastConstants.END_OF_STREAM, "The end of the input stream has been reached.");
  22. return null; // short circuit if global error handler does not throw exception
  23. }
  24. encoding[i] = (byte) nextByte;
  25. } catch (IOException e) {
  26. Global.handleError(FastConstants.IO_ERROR, "A IO error has been encountered while decoding.", e);
  27. return null; // short circuit if global error handler does not throw exception
  28. }
  29. return new ByteVectorValue(encoding);
  30. }

Unicode字符串类型编码类

org.openfast.template.type.codec.UnicodeString

这个类型和上面的字节流编码类逻辑一样。

fast协议解读的更多相关文章

  1. IP协议解读(二)

    IP协议是TCP协议栈中的核心协议,也是网络编程的基础之中的一个. 我们接着在IP协议解读(一)继续学习 网络层作用 IP分片: IP数据报的长度超过帧的MTU时,将会被分片传输. 分片可能发生在发送 ...

  2. SD3.0四个协议解读

    前面的文章提到过SD卡主要分为两个操作模式,一是初始化和识别操作模式.还有一种就是这篇文章须要分析的传输数据模式啦. 传输数据模式: 传输数据模式主要有六种状态,各自是Stand-by状态.Trans ...

  3. OAuth 2.0 / RCF6749 协议解读

    OAuth是第三方应用授权的开放标准,目前版本是2.0版,以下将要介绍的内容和概念主要来源于该版本.恐篇幅太长,OAuth 的诞生背景就不在这里赘述了,可参考 RFC 6749 . 四种角色定义: R ...

  4. IP协议解读(三)

    今天我们来介绍网络层中的ICMP协议 ICMP报文格式 图一: 从图片上我们能够分析出.前三位的字段都是固定的.8位类型字段,8位代码字段.16位校验和字段.其它字段因ICMP报文类型不同而不同.8位 ...

  5. DDS协议解读及测试开发实践

    DDS概述 DDS是OMG在2004年发布的中间件协议和应用程序接口(API)标准,它为分布式系统提供了低延迟.高可靠性.可扩展的通信架构标准.DDS目前在工业.医疗.交通.能源.国防领域都有广泛的应 ...

  6. SMTP协议解读以及如何使用SMTP协议发送电子邮件

    电子邮件协议中POP3协议用于接收邮件,SMTP协议用于发送邮件.SMTP的全称为Simple Mail Transfer Protocol,也就是简单邮件传输协议,字如其名.   相较于POP3而言 ...

  7. OpenID Connect:OAuth 2.0协议之上的简单身份层

    OpenID Connect是什么?OpenID Connect(目前版本是1.0)是OAuth 2.0协议(可参考本人此篇:OAuth 2.0 / RCF6749 协议解读)之上的简单身份层,用 A ...

  8. 一文让你秒懂互联网TCP/IP协议的深层含义

    什么是 TCP/IP 协议 首先,协议,可以理解为是一套统一的规则,就像行业标准.由于互联网主要的功能是传输信息,所以其协议一般是管理系统之间如何相互通信的规则. 用邮政和物流等线下的“运输协议”来理 ...

  9. onvif 协议

    1.ONVIF 协议解读 https://www.onvif.org 一.什么是ONVIF? 1.1形成 2008年5月,由安讯士(AXIS)联合博世(BOSCH)及索尼(SONY)公司三方宣布携手共 ...

随机推荐

  1. SpringMVC控制器 跳转到jsp页面 css img js等文件不起作用 不显示

    今天在SpringMVC转发页面的时候发现跳转页面确实成功,但是JS,CSS等静态资源不起作用: 控制层代码: /** * 转发到查看培养方案详情的页面 * @return */ @RequestMa ...

  2. connect by和strart with子句

    --使用connect by和strart with子句 SELECT [level],column,expression, ... FROM table [WHERE where_clause] [ ...

  3. python进阶之类常用魔法方法和魔法属性

    前言 前面我们总结过了python的关键字.运算符.内置函数.语法糖等与python魔法方法之间的关系,现在我们更细一点,看看python的面向对象编程有哪些常用的魔法属性和魔法方法. 魔法属性 对于 ...

  4. aarch64_o2

    opensips-event_rabbitmq-2.2.3-1.fc26.aarch64.rpm 2017-03-10 01:22 42K fedora Mirroring Project opens ...

  5. Python Challenge 第 5 关攻略:peak

    # -*- coding: utf-8 -*- # @Time : 2018/9/26 14:03 # @Author : cxa # @File : pickledemo.py # @Softwar ...

  6. IDL界面程序直接调用envi菜单对应功能

    参考自http://blog.sina.com.cn/s/blog_764b1e9d010115qu.html 参考文章的方法是构建一个button控件,通过单击实现,这种方法比较复杂,不是我们经常能 ...

  7. html5新增表单元素

    1.验证 <form> <input type="email"></input>    验证邮箱 <input type="ur ...

  8. MVC Ajax Form & Ajax Valida(笔记)

    1.引入必要的文件 <script src=.min.js")" type="text/javascript"></script> &l ...

  9. Mac 升级一次,php 就崩溃一次,有味,苹果....

    Mac升级系统macOS Sierra后PHP不编译 Mac下搭建PHP开发环境(Apache+PHP+MySQL+phpMyAdmin),当Mac 从OS 10.11升级至macOS Sierra( ...

  10. less常用样式集,清除浮动、背景自适应、背景渐变、圆角、内外阴影、高度宽度计算。

    .clear-float() { content: ''; display: block; clear: both; height:; } //伪元素清除浮动 .after-clear() { &am ...