股票行情一般传输的数据类型为: 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占用字节(62) + value(42 + 4*4)=36字节
同样的数据,如果使用fast协议传输需要字节数: tag(61) +value(4+ 3 + 43)=29字节
fast协议特征基本特征:
每个byte的最高位用0表示当前字节属于该字段,用1表示这是该字段的最后一个字节
fast协议传输过程中不会传输float/double类型的数据,而是将其根据小数位扩展成数字类型。
数字类型在传输过程中,可以为1,2,3,4,5,6,7,8,9,10个字节,具体要根据是否为有符号、无符号、以及数字的范围来具体确定占用几个字节
在传输数字时,如果涉及到有符号数的时候,第一个字节的第2位用来表示符号,0表示正数,1表示负数。
在传输ascii编码类型的时候,占用1个字节。ascii编码本身第一位为0,,所以一个字节是符合fast协议规定的。
在传输unicode编码类型的时候,使用(count,真正数据)来传输,count代表数据真正占用的字节数。
在传输byte流的时候,和unicode编码一样,也使用(count,真正数据)来传输。
在传输unicode 和byte流的时候不使用停止位特征,即每个字节的最高位为真实数据
下面代码出自:openfast-1.1.1
fast协议解读 停止位org.openfast.template.type.codec
/** * 数据编码成功后,将最后一个字节的首位设置成1,即为停止位 * * */ public byte[] encode(ScalarValue value) { byte[] encoding = encodeValue(value); encoding[encoding.length - 1] |= 0x80; return encoding; } 有符号数编码类类:org.openfast.template.type.codec.SignedInteger
/** * 编码方法 * */ public byte[] encodeValue(ScalarValue value) { long longValue = ((NumericValue) value).toLong(); int size = getSignedIntegerSize(longValue); byte[] encoding = new byte[size]; //组装数据,即每个字节第一位不表示数据;组装完成后仍然是大端序列(低字节位为值得高有效位) for (int factor = 0; factor < size; factor++) { //0x3f = 0011 1111 //0x7f = 0111 1111 int bitMask = (factor == (size - 1)) ? 0x3f : 0x7f; encoding[size - factor - 1] = (byte) ((longValue >> (factor * 7)) & bitMask); } // Get the sign bit from the long value and set it on the first byte // 01000000 00000000 ... 00000000 // ^----SIGN BIT //将一个字节的第二位设置为符号位, 0表示正数;1表示负数 encoding[0] |= (0x40 & (longValue >> 57)); return encoding; } /** * 解码方法 * */ public ScalarValue decode(InputStream in) { long value = 0; try { // IO read方法如果返回小于-1的时候,表示结束;正常范围0-255 int byt = in.read(); if (byt < 0) { Global.handleError(FastConstants.END_OF_STREAM, "The end of the input stream has been reached."); return null; // short circuit if global error handler does not throw exception } //通过首字节的第二位与运算,确认该数据的符号 if ((byt & 0x40) > 0) { value = -1; } //到此,value的符号已经确定, //value=0 则该数为负数, value= -1该数为正数 // int value = -1 16进制为 0xFF FF FF FF // int value = 0 16进制为 0x00 00 00 00 //下面的只是通过位操作来复原真实的数据 value = (value << 7) | (byt & 0x7f); //(value << 7)确保最后7位为0; (byt & 0x7f) 还是byt while ((byt & 0x80) == 0) { //根据第一位来判断当前byte是否属于这个字段 byt = in.read(); if (byt < 0) { Global.handleError(FastConstants.END_OF_STREAM, "The end of the input stream has been reached."); return null; // short circuit if global error handler does not throw exception } value = (value << 7) | (byt & 0x7f); //先把有效位往左移7位,然后再处理当前的七位 } } catch (IOException e) { Global.handleError(FastConstants.IO_ERROR, "A IO error has been encountered while decoding.", e); return null; // short circuit if global error handler does not throw exception } return createValue(value); } 无符号数编码类org.openfast.template.type.codec.UnsignedInteger
/** * 编码方法 * */ public byte[] encodeValue(ScalarValue scalarValue) { long value = scalarValue.toLong(); int size = getUnsignedIntegerSize(value); byte[] encoded = new byte[size]; for (int factor = 0; factor < size; factor++) { encoded[size - factor - 1] = (byte) ((value >> (factor * 7)) & 0x7f); } return encoded; } /** * * 解码方法 * */ public ScalarValue decode(InputStream in) { long value = 0; int byt; try { do { byt = in.read(); if (byt < 0) { Global.handleError(FastConstants.END_OF_STREAM, "The end of the input stream has been reached."); return null; // short circuit if global error handler does not throw exception } value = (value << 7) | (byt & 0x7f); } while ((byt & 0x80) == 0); } catch (IOException e) { Global.handleError(FastConstants.IO_ERROR, "A IO error has been encountered while decoding.", e); return null; // short circuit if global error handler does not throw exception } return createValue(value); } AsciiString编码类