公司项目需要对接嵌入式设备,底层stm32
使用的是TCP网络协议,go语言中原生TCP编程还是比较简单的,像网络方面的编程,其实很多操作都比较繁复,在编写时,就希望能够有类似的框架性质的库帮助统一所有网络的代码,以及减轻网络编写的负担。
找到一个项目,link 。
就像它README所说的,它不是一个完整网络层也不是一个框架,它只是一个脚手架,它可以帮助你快速的实现出你所需要的网络层或者通讯框架,帮你约束网络层的实现方式,不至于用不合理的方式实现网络层,除此之外它不会管更多的事情。
这样的话其实也就足够使用了,毕竟我要的功能并不复杂,仅需要为了屏蔽掉一些细节问题,除此之外,好像也并不需要什么多余的东西了。
bug fix
仓库中有对json
解码的原生支持,但其中似乎存在一些问题,这里补齐一下。
当client端发送的数据为空时,这里会传入nil,也就会出现panic,需要判断body是否为空。
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 --- a/codec/json.go +++ b/codec/json.go @@ -2 ,7 +2 ,6 @@ package codec import ( "encoding/json" - "errors" "io" "reflect" @@ -74 ,18 +73 ,10 @@ func (c *jsonCodec) Receive () (interface {}, error) { return nil , err } var body interface {} + if in.Head != "" { if t, exists := c.p.types[in.Head]; exists { body = reflect.New(t).Interface() + } else { + return nil , errors.New("Receive Json have no Head match, Close connection" ) } + } + if in.Body == nil { + return nil , errors.New("Receive Json have no Body field, Close connection" ) } err = json.Unmarshal(*in.Body, &body)
另外还有一处编译的地方,对于win32位来说会报错的地方。
math.MaxUint32
会超出win32位int
的大小,当然这是在编译时就会报错(并不会直接按照类型大小截取大小,反而会直接丢出错误)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 --- a/codec/fixlen.go +++ b/codec/fixlen.go @@ -54 ,11 +54 ,17 @@ func FixLen (base link.Protocol, n int , byteOrder binary.ByteOrder, maxRecv, maxS byteOrder.PutUint16(b, uint16 (size) ) } case 4: - if maxRecv > math .MaxUint32 {- maxRecv = math.MaxUint32 + + + + + + + if maxRecv > math.MaxInt32 { + maxRecv = math.MaxInt32 } - if maxSend > math.MaxUint32 { - maxSend = math.MaxUint32 + if maxSend > math.MaxInt32 { + maxSend = math.MaxInt32 }
自定义codec
和底层的通信采用字节流,需要自定义协议进行操作。这里只需要参照codec里面的协议,自定义一个协议就可以了。
codec
其实很好理解,相当于socket的句柄传入包中,由包中函数进行自定义处理数据。
需要注意的一点是:io.Reader
类的read
函数传入的参数,是一个len不为零的byte的数组,也就是有接收数据的空间,需要提前分配,这里是我在编写的时候不注意的地方,测试程序的read老是过不去。
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 package codecimport ( "errors" "io" "gitlab.com/link" ) type ByteProtocol struct { } func (b *ByteProtocol) NewCodec (rw io.ReadWriter) (link.Codec, error) { codec := &byteCodec{ p: b, r: rw, w: rw, } codec.closer, _ = rw.(io.Closer) return codec, nil } func Byte () *ByteProtocol { return &ByteProtocol{ } } type byteCodec struct { r io.Reader w io.Writer p *ByteProtocol closer io.Closer } func (c *byteCodec) Receive () (interface {}, error) { recvData := make ([]byte , 4092 ) cnt, err := c.r.Read(recvData) return recvData[:cnt], err } func (c *byteCodec) Send (msg interface {}) error { b, ok := msg.([]byte ) if !ok { return errors.New("Send Byte Format Error" ) } _, err := c.w.Write(b) return err } func (c *byteCodec) Close () error { if c.closer != nil { return c.closer.Close() } return nil }
以上还可以将reader改为bufio.Reader
和bufio.Writer
,但记住,带缓冲的IO,在写完数据后,一定要去记得显示调用Flush()
函数,不然数据不会写入的。
建议使用bufio
,例如可以使用peek
函数,读取协议包(自定义)中实际大小,通过实际的大小去读取data
数据,可以设计用来解决TCP沾包的问题。
Receive()
中使用for循环读取包,当然这里调用Receive()
就要用到Goroutine
,然后数据通信则使用channel进行通信,我在实际的程序中就是这样操作的。
本文标题: funny/link TCP库的使用和bug fix
文章作者: 小师
发布时间: 2019-06-06
最后更新: 2022-04-07
原始链接: chunlife.top/2019/06/06/funny-link-TCP库的使用和bug-fix/
版权声明: 本站所有文章均采用知识共享署名4.0国际许可协议进行许可