go语言渐入佳境-网络[9]-asn.1

Abstract Syntax Notation One(ASN.1)最初是在1984年为电信行业设计的。 ASN.1是一个复杂的标准,Go在包“asn1”中支持它的一个子集。 它从复杂的数据结构构建自描述的序列化数据。 它在当前网络系统中的主要用途是作为在认证系统中大量使用的X.509证书的编码。 Go中的支持基于读取和写入X.509证书所需的内容。

两个函数允许我们编码和解码数据:

1
2
func Marshal(val interface{}) ([]byte, os.Error)
func Unmarshal(val interface{}, b []byte) (rest []byte, err os.Error)

asn.1编码与解码整数

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
/* ASN.1
*/

package main

import (
"encoding/asn1"
"fmt"
"os"
)

func main() {
mdata, err := asn1.Marshal(13)
checkError(err)

var n int
_, err1 := asn1.Unmarshal(mdata, &n)
checkError(err1)

fmt.Println("After marshal/unmarshal: ", n)
}

func checkError(err error) {
if err != nil {
fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
os.Exit(1)
}
}

为了管理更复杂的数据类型,我们必须更仔细地研究ASN.1支持的数据结构,以及如何在Go中完成ASN.1支持。

任何序列化方法都能够处理某些数据类型而不处理其他数据类型。 因此,为了确定任何序列化(如ASN.1)的适用性,您必须查看支持的可能数据类型与您希望在应用程序中使用的数据类型。 以下ASN.1类型取自http://www.obj-sys.com/asn1tutorial/node4.html

简单的类型是:

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
s := "hello"
mdata, _ := asn1.Marshal(s)

var newstr string
asn1.Unmarshal(mdata, &newstr)

t := time.LocalTime()
mdata, err := asn1.Marshal(t)

var newtime = new(time.Time)
_, err1 := asn1.Unmarshal(&newtime, mdata)

// using variables
var t1 T
t1 = ...
mdata1, _ := asn1.Marshal(t)

var newT1 T
asn1.Unmarshal(&newT1, mdata1)

/// using pointers
var t2 = new(T)
*t2 = ...
mdata2, _ := asn1.Marshal(*t2)

var newT2 = new(T)
asn1.Unmarshal(newT2, mdata2)

asn.1 服务器-客户端例子

服务器:

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
/* ASN1 DaytimeServer
*/
package main

import (
"encoding/asn1"
"fmt"
"net"
"os"
"time"
)

func main() {

service := ":1200"
tcpAddr, err := net.ResolveTCPAddr("tcp", service)
checkError(err)

listener, err := net.ListenTCP("tcp", tcpAddr)
checkError(err)

for {
conn, err := listener.Accept()
if err != nil {
continue
}

daytime := time.Now()
// Ignore return network errors.
mdata, _ := asn1.Marshal(daytime)
conn.Write(mdata)
conn.Close() // we're finished
}
}

func checkError(err error) {
if err != nil {
fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
os.Exit(1)
}
}

客户端:

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
/* ASN.1 DaytimeClient
*/
package main

import (
"encoding/asn1"
"fmt"
"io/ioutil"
"net"
"os"
"time"
)

func main() {
if len(os.Args) != 2 {
fmt.Fprintf(os.Stderr, "Usage: %s host:port", os.Args[0])
os.Exit(1)
}
service := os.Args[1]

conn, err := net.Dial("tcp", service)
checkError(err)

defer conn.Close()

result, err := ioutil.ReadAll(conn)
checkError(err)

var newtime time.Time
_, err1 := asn1.Unmarshal(result, &newtime)
checkError(err1)

fmt.Println("After marshal/unmarshal: ", newtime.String())

os.Exit(0)
}

func checkError(err error) {
if err != nil {
fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
os.Exit(1)
}
}

测试:

1
2
3
4
5
6
服务器:
$ go build .
jacksondeMacBook-Pro:net jackson$ ./net
客户端:
$ ./client 127.0.0.1:1200
After marshal/unmarshal: 2019-01-19 12:32:47 +0800 CST