1、背景介绍
因工作接触到半导体行业,主要负责 EAP 相关的东西,其中需要实现 SECS/GEM 协议,消息协议使用的是 SECS-II
,其中有一种数据类型是 A
类型,表示字符串类型。需要将接收到的 SECS 指令记录在日志中,以及反解析 SECS 指令。
我们知道,网络中接受到的数据都是 byte
,需要自己根据规则来进行序列化和反序列化,像平常我们使用 HTTP 通信时,都是使用第三方通信库,底层的实现已经封装好了。
比如我们规定现在传输过来的数据表示的是ASCII
码,那此时byte = 65
表示的是 字符A
,我们把这一步叫做序列化,现在需要把 字符A
转换为byte = 65
,就叫做反序列化。
知道上面的规则定义后,来看看现在的具体需求,需求蛮简单,就是在收到数据后,将其序列化后存储在日志后,方便后续的维护以及排查问题等,还有一个功能是可以将日志中的 SECS 指令导入到模拟器中(其实就是将 日志中的 SECS 指令反序列化为 byte 数据)。
2、数据如何序列化和反序列化的思考
知道需求后,就开始想想怎么来实现。
因为使用的是 golang 作为开发语言,所以接下来讲解都是基于 go ,不过不同语言关于这块应该大差不差。
最简单的想法就是使用 golang 的格式化字符串中的 %S
来序列化数据,这样简单也方便,其实大多数情况下是可以的,不过有一个问题就是,当遇到ASCII
中的控制字符时,这种方式就不太行了。
比如 ASCII=10 (LF) - 换行:n
格式化后,记录日志时就直接换行了,日志会乱七八糟的换行,这种可能还可以接受,如果接收到的数据是6 (ACK) - 应答:不常用
这样的时候,使用%s
得到的结果是看不错效果的,那更加谈不上反序列化了。
那怎么解决呢?
对于 go 有一种简便方式,使用 go 中的格式化方式 %q
,该值对应的单引号括起来的go语法字符字面值,必要时会采用安全的转义表示.
。是不是看着一头雾水,其实就是使用特殊的字符串代替 ASCII
中的控制字符,接下来看看是如何表示的。
控制字符采用以下方式:
ascii: 0 "x00"
ascii: 1 "x01"
ascii: 2 "x02"
ascii: 3 "x03"
ascii: 4 "x04"
ascii: 5 "x05"
ascii: 6 "x06"
ascii: 7 "a"
ascii: 8 "b"
ascii: 9 "t"
ascii: 10 "n"
ascii: 11 "v"
ascii: 12 "f"
ascii: 13 "r"
ascii: 14 "x0e"
ascii: 15 "x0f"
ascii: 16 "x10"
ascii: 17 "x11"
ascii: 18 "x12"
ascii: 19 "x13"
ascii: 20 "x14"
ascii: 21 "x15"
ascii: 22 "x16"
ascii: 23 "x17"
ascii: 24 "x18"
ascii: 25 "x19"
ascii: 26 "x1a"
ascii: 27 "x1b"
ascii: 28 "x1c"
ascii: 29 "x1d"
ascii: 30 "x1e"
ascii: 31 "x1f"
ascii: 127 "x7f"
ascii: 92 ""
知道了上面的规定后,那后面的编码就简单很多了,下面贴下自己的代码。
3、代码实现
3.1、byte转字符串的方式
package main
import (
"fmt"
"unicode"
)
var controlCharters = make([]byte, 33)
var controlCharterMaps = make(map[byte]byte)
func init() {
for i := 0; i
输出结果:
x00x01x02x03x04x05x06abtnvfrx0ex0fx10x11x12x13x14x15x16x17x18x19x1ax1bx服务器托管网1cx1dx1ex1f !"#$%&'()*+,-./0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~x7f
3.2、字符串转byte的方式
package main
import (
"errors"
"fmt"
"strings"
"unicode"
)
var controlCharters = make([]byte, 33)
var controlCharterMaps = make(map[byte]byte)
func init() {
for i := 0; i ?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~x7f"
unescaped, err := replaceControlCharacters(s)
if err != nil {
fmt.Printf("err: %s", err)
return
}
fmt.Println([]byte(unescaped))
}
// replaceControlCharacters 将 sml 中表示为控制字符以及转义字符() 转换为 ascii 字符
func replaceControlCharacters(input string) (string, error) {
controlCharMap := map[string]string{
"\": "",
"n": "n",
"t": "t",
"r": "r",
"b": "b",
"a": "a",
"f": "f",
"v": "v",
"x00": "x00",
"x01": "x01",
"x02": "x02",
"x03": "x03",
"x04": "x04",
"x05": "x05",
"x06": "x06",
"x0e": "x0e",
"x0f": "x0f",
"x10": "x10",
"x11": "x11",
"x12": "x12",
"x13": "x13",
"x14": "x14",
"x15": "x15",
服务器托管网"x16": "x16",
"x17": "x17",
"x18": "x18",
"x19": "x19",
"x1a": "x1a",
"x1b": "x1b",
"x1c": "x1c",
"x1d": "x1d",
"x1e": "x1e",
"x1f": "x1f",
"x7f": "x7f",
}
var output strings.Builder
i := 0
for i
输出方式:
[0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127]
从上面可以看出,方式还是很简单的,其实还有很多其他方式可以达到序列化以及反序列化的方式,比如将收到的数据使用 base64
等方式,这样可以的。只不过因为我们的日志还需要给到客户看,使用 base64 并不友好(自己平时看也不方便),所以需要使用上面这种方式。
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
1、SQL92语法 连接查询:也可以叫跨表查询,需要关联多个表进行查询 1.1显示每个员工信息,并显示所属的部门名称 以上输出,不正确,输出了56条数据,其实就是两个表记录的乘积,这种情况我们称为:“笛卡儿乘积”,出现错误的原因是:没有指定连接条件 1.2指定…