加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

2. 使用golang特性编写的程序结构

发布时间:2020-12-16 18:16:14 所属栏目:大数据 来源:网络整理
导读:所有的服务器都有相似的程序结构 net.Conn 的 Write 和 Read 方法都是阻塞式执行的,所以要 为每个 TCP 连接创建两个协程,分别用来接收和发送数据 .在接收协程中计算生成的数据,要发送给对端时,常规做法是生成一个 []byte 切片 ------ buf := make( []byte,len
所有的服务器都有相似的程序结构

net.Conn 的 Write 和 Read 方法都是阻塞式执行的,所以要 为每个 TCP 连接创建两个协程,分别用来接收和发送数据.在接收协程中计算生成的数据,要发送给对端时,常规做法是生成一个 []byte 切片 ------ buf := make( []byte,length),然后把计算生成的数据拷贝到 buf 中,再投递到类型是 chan []byte 的 channel 中.发送协程只做一件事,从 channel 中取出数据并发送给对端

在上面所述的接收协程中,buf := make( []byte,length) 这行代码可以用内存池进行优化,内存池的实现可以选用达达的开源代码: https://github.com/funny/slab
在登录服务器 login 和网关服务器 gate 中,会建立数千个 TCP 连接数/协程数,在这两种服务器上选用的内存池类型是基于 golang 临时对象池的 slab.SyncPool;而大厅服务器 lobby 和路由服务器 route 的 TCP 连接数/协程数(几个至几十个不等)几乎是固定的,在这两种服务器上选用的内存池类型是基于 channel 的 slab.ChanPool;发送协程中把 buf 从 channel 中取出并发送完后,需要把 buf 回收进内存池

为了处理TCP的粘包情况,定义TCP数据逻辑包(以下简称逻辑包)格式为 包头 + 数据体;包头是两个 int32 字段,共计8字节,第一个 int32 字段表示协议号,第二个 int32 字段表示随后的数据体;比如客户端发送长度为 3 的帐号字符串 "abc" 给登录服务器login,则逻辑包包头的协议号字段可以约定填 1,数据长度填 3,逻辑包的数据体就是字符串 "abc"
逻辑包是自取的名字,在不同的团队可能有不同的称呼,是指在应用层提交的一段 TCP 数据,能够完整的表示上层业务逻辑意义,并非底层(网卡或者 TCP/IP 层)上的数据包.在不同的团队定义的格式也可能不同,但目的都是为了处理粘包


golang 中处理粘包可以使用 io.ReadFull 和 bufio.Reader,具体用法:

// c 表示刚创建的 net.Conn r := bufio.NewReaderSize( c,1024 ) recvBuf := make( []byte,1024 ) io.ReadFull( r,recvBuf[ :8 ] ) // 先读取包头,收到 8 个字节才继续往下执行,否则一直阻塞 dataBodyLen := binary.BigEndian.Uint32( recvBuf[4:]) // 读取包头中的数据体长度 io.ReadFull( read,recvBuf[ 8: 8 + dataBodyLen ] ) // 执行完这一句后,recvBuf 中保存的就是一个完整的逻辑包了,完整逻辑包的长度是 8 + dataBodyLen

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读