因为很不满意 tcpsock 的设计与实现,及有意专为譬如游戏服务器端开发设计一套 TCP 网络库,所以年初即有了 tcpsock.v2 的开发计划,于是粗略整理出了以下几条目标计划:

    1) TcpConn 的 ID 类型由 uint32 升级为 uint64
    2) 比较灵活的 Create / Config Options 支持
    3) 以队列的方式实现数据发送等逻辑
    4) 库代码最好不使用反射
    5) 对游戏服务器端开发友好(TCP ONLY)
    6) TcpServer 增加诸如 Iterate、Send、Kick 等常用接口
    7) 回调、超时、重连等逻辑的整理优化与支持等

  而截至目前,除了第 2 条, tcpsock.v2 基本初步实现了以上目标(譬如重连,可能在应用层实现更合适),但不少设计实现或还比较粗糙,我应该会在测试及使用中对之慢慢修补改进增强(不排除后期再开发一套全新的库)。其改动较大的部分设计实现,如下可见一斑(conn.go):

// Copyright (C) 2018 ecofast(胡光耀). All rights reserved.
// Use of this source code is governed by a BSD-style license. package tcpsock import (
"errors"
"net"
"sync"
"sync/atomic"
"time"
) const (
RecvBufLenMax = 4 * 1024
SendBufLenMax = 24 * 1024
TcpBufLenMax = 4 * 1024
) type queueNode struct {
buf []byte
next *queueNode
} type TcpConn struct {
id uint64
owner *tcpSock
conn net.Conn
closeChan chan struct{}
closeOnce sync.Once
closedFlag int32
onClose OnTcpDisconnect mutex sync.Mutex
firstSendNode *queueNode
lastSendNode *queueNode sendBuf [SendBufLenMax]byte
bufLen int onRead func(p []byte) (n int, err error)
} func newTcpConn(id uint64, owner *tcpSock, conn net.Conn, onClose OnTcpDisconnect) *TcpConn {
return &TcpConn{
id: id,
owner: owner,
conn: conn,
closeChan: make(chan struct{}),
onClose: onClose,
}
} func (self *TcpConn) ID() uint64 {
return self.id
} func (self *TcpConn) Write(b []byte) (n int, err error) {
if self.closed() {
return 0, errors.New("connection closed")
} cnt := len(b)
if cnt == 0 || cnt > SendBufLenMax {
return 0, errors.New("invalid data")
} node := &queueNode{}
node.buf = make([]byte, cnt)
copy(node.buf, b)
self.mutex.Lock()
if self.lastSendNode != nil {
self.lastSendNode.next = node
}
if self.firstSendNode == nil {
self.firstSendNode = node
}
self.lastSendNode = node
self.mutex.Unlock()
return cnt, nil
} func (self *TcpConn) Close() error {
self.closeOnce.Do(func() {
atomic.StoreInt32(&self.closedFlag, 1)
close(self.closeChan)
self.conn.Close()
if self.onClose != nil {
self.onClose(self)
}
self.clear()
})
return nil
} func (self *TcpConn) closed() bool {
return atomic.LoadInt32(&self.closedFlag) == 1
} func (self *TcpConn) RawConn() net.Conn {
return self.conn
} func (self *TcpConn) run() {
startGoroutine(self.send, self.owner.waitGroup)
startGoroutine(self.recv, self.owner.waitGroup)
} func startGoroutine(fn func(), wg *sync.WaitGroup) {
wg.Add(1)
go func() {
fn()
wg.Done()
}()
} func (self *TcpConn) clear() {
self.mutex.Lock()
defer self.mutex.Unlock()
self.firstSendNode = nil
self.lastSendNode = nil
self.bufLen = 0
} func (self *TcpConn) getSendBuf() []byte {
self.mutex.Lock()
defer self.mutex.Unlock() for self.firstSendNode != nil {
node := self.firstSendNode
self.firstSendNode = node.next
copy(self.sendBuf[self.bufLen:], node.buf)
self.bufLen += len(node.buf)
if self.bufLen >= TcpBufLenMax {
break
}
} if self.firstSendNode == nil {
self.lastSendNode = nil
} l := self.bufLen
if l > TcpBufLenMax {
l = TcpBufLenMax
}
if l > 0 {
b := make([]byte, l)
copy(b, self.sendBuf[:l])
self.bufLen -= l
if self.bufLen > 0 {
copy(self.sendBuf[0:], self.sendBuf[l:])
}
if self.bufLen < 0 {
self.bufLen = 0
}
return b
} return nil
} func (self *TcpConn) send() {
defer func() {
recover()
self.Close()
}() for {
if self.closed() {
return
} select {
case <-self.owner.exitChan:
return case <-self.closeChan:
return default:
if b := self.getSendBuf(); b != nil {
if n, err := self.conn.Write(b); err != nil || n != len(b) {
// to do
//
return
}
} else {
time.Sleep(5 * time.Millisecond)
}
}
}
} func (self *TcpConn) recv() {
defer func() {
recover()
self.Close()
}() buf := make([]byte, RecvBufLenMax)
for {
select {
case <-self.owner.exitChan:
return case <-self.closeChan:
return default:
} cnt, err := self.conn.Read(buf)
if err != nil || cnt == 0 {
return
}
if self.onRead != nil {
if n, err := self.onRead(buf[:cnt]); n != cnt || err != nil {
// to do
//
return
}
}
}
}

  基于 tcpsock.v2,我编写了个简单的聊天室,包括服务器端及客户端机器人等,其设计及实现或许能部分演示如何使用 tcpsock.v2 开发基于 TCP 协议的服务器端程序。当然单就这个聊天室而言,性能上应还有明显的可提升空间(设计上的调整与优化)。

  相较 Redis / Memcached,可能 groupcache 并不怎么知名(当然它们的设计使用场景差异很大),它的作者其实正是写出 Memcached 的那个大牛。早前我在阅读 groupcache 部分代码的时候,有时却居然有一种恍若几年前阅读范哥编写的一些基础库代码的感觉,譬如 consistenthash,譬如 lru,看起来平实无华没有半点所谓奇技或淫巧,但我相信,没有深厚的功底,断难写出这样的高质量实现(不才深感学识距大牛隔了数条街)。

  去年初的时候,因兴趣练手之故,我有写过一个简单的基于 TCP 的文件下载服务器。而其实,它和 groupcache 的使用场景很相似,只是后者使用了 HTTP 且不太容易适配某些使用场景等。于是我想,能否部分参考 groupcache,也编写个基于 TCP 的 cacheserver 呢?于是便有了 ecocache 的开发计划。

  一开始,ecocache 只是单纯地想设计成类似 groupcache 的缓存服务器,但前者将是完整的程序并能定制提供数据获取等实现(譬如以动态库的方式),如此 ecocache 即既能作为譬如文件下载服务器,亦能在一些场合取代 Redis 等。但在开发过程中却总觉得,作为完整的程序,若 ecocache 提供以动态库的方式来定制实现数据获取,既增加了复杂度,也使得代码看上去挺 ugly。综合考虑之下,ecocache 对外将只提供譬如 GET、SET 等有限功能,且通讯协议也会足够简单:

const (
CmSmDif = 127 CM_REGSVR = 1
SM_REGSVR = CmSmDif + CM_REGSVR CM_DELSVR = 2
SM_DELSVR = CmSmDif + CM_DELSVR CM_REQSVR = 3
SM_REQSVR = CmSmDif + CM_REQSVR CM_PING = 4
SM_PING = CmSmDif + CM_PING CM_GET = 5
SM_GET = CmSmDif + CM_GET CM_SET = 6
SM_SET = CmSmDif + CM_SET
) const (
SizeOfPacketHeadLen = 4
SizeOfPacketHeadCmd = 1
SizeOfPacketHeadRet = 1
SizeOfPacketHeadParam = 2
SizeOfPacketHead = SizeOfPacketHeadLen + SizeOfPacketHeadCmd + SizeOfPacketHeadRet + SizeOfPacketHeadParam
) type Head struct {
Len uint32
Cmd uint8
Ret uint8
Param uint16
} type Body struct {
Content []byte
} type Packet struct {
Head
Body
}

  ecocache 的架构图基本如下:

  1) cacheserver 分布式部署,相互之间没有交互,且都与 load balancer 保持连接(当然 load balancer 并非必须)

  2) load balancer 以一致性哈希的方式为客户端提供一个可用的 cacheserver 地址

  3) 客户端连接至此 cacheserver,继而 GET、SET 等

  而其实,ecocache 更适合使用在只有或绝多都是 GET 的场景下,SET 的实现尚很粗糙原始。实际使用上,应先预热缓存。

  基本上,ecocache 也比较可能会慢慢修补改进。

tcpsock.v2 与 ecocache的更多相关文章

  1. 如何搭建自己的SPRING INITIALIZR server

    这两天在慕课学Spring boot ,用idea通过spring initializr新建项目 即使用代理连不上.无奈. 参考了 GitHub - spring-io/initializr: A w ...

  2. Atitit. 破解  拦截 绕过 网站 手机 短信 验证码  方式 v2 attilax 总结

    Atitit. 破解  拦截 绕过 网站 手机 短信 验证码  方式 v2 attilax 总结 1. 验证码的前世今生11.1. 第一代验证码 图片验证码11.2. 第二代验证码  用户操作 ,比如 ...

  3. [Android]Android端ORM框架——RapidORM(v2.1)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/6020412.html [Android]Android端ORM ...

  4. [Android]Android端ORM框架——RapidORM(v2.0)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5626716.html [Android]Android端ORM ...

  5. JuCheap V2.0响应式后台管理系统模板正式发布beta版本

    JuCheap V1.* 查看地址: http://blog.csdn.net/allenwdj/article/details/49155339 经过半年的努力,JuCheap后台通用响应式管理后台 ...

  6. Atitit. 项目文档目录大纲 总集合  v2

    Atitit. 项目文档目录大纲 总集合  v2 -----Atitti.原有项目源码的架构,框架,配置与环境说明 v3 q511 -----Atitit.开发环境 与 工具 以及技术框架 以及 注意 ...

  7. python gettitle v2.0

    #!/usr/bin/env python # coding=utf-8 import threading import requests import Queue import sys import ...

  8. ".NET Compact Framework v2.0 could not be found."

    参考: http://blog.csdn.net/godcyx/article/details/7348431 问题原因: That's a known issue where VS can't di ...

  9. ASP.NET Identity V2

    Microsoft.AspNet.Identity是微软在MVC 5.0中新引入的一种membership框架,和之前ASP.NET传统的membership以及WebPage所带来的SimpleMe ...

随机推荐

  1. C语言提高 (3) 第三天 二级指针的三种模型 栈上指针数组、栈上二维数组、堆上开辟空间

    1 作业讲解 指针间接操作的三个必要条件 两个变量 其中一个是指针 建立关联:用一个指针指向另一个地址 * 简述sizeof和strlen的区别 strlen求字符串长度,字符数组到’\0’就结束 s ...

  2. .net 导入Excel

    今天我在做导入Excel的时候遇到了一些问题,顺便说句其实我很少做这方面的!我的需求是导入EXCEL 验证数据正确性 并把数据显示到页面 如有错误信息则弹出来 那具体问题是什么呢? 导入Excel有2 ...

  3. Unsupported platform for fsevents@1.2.3: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})

    系统:win10 使用 npm 安装依赖时报错: Unsupported platform for fsevents@1.2.3: wanted {"os":"darwi ...

  4. oracle 创建自增主键

    1.创建表 create table Test_Increase( userid number(10) NOT NULL primary key, /*主键,自动增加*/ username varch ...

  5. Java基础学习总结(63)——Java集合总结

    数据结构是以某种形式将数据组织在一起的集合,它不仅存储数据,还支持访问和处理数据的操作.Java提供了几个能有效地组织和操作数据的数据结构,这些数据结构通常称为Java集合框架.在平常的学习开发中,灵 ...

  6. nodejs-循环

    for循环 for(var key in object){ consol.log('wor' : key); } 来自为知笔记(Wiz)

  7. C#中的LINQ 基础

    1.LINQ的数据源 必须可枚举的,即必须是数组或者集合 (继承了IEnumerable<T>接口就可以,注意是IEnumerable<T>,不是IEnumerable接口,不 ...

  8. AS常见的错误

    导入的项目使用的gradle版本和本地的要一致,不然会提示类似"Minimum supported Gradle version is 3.3. Current version is 2.1 ...

  9. 2016.3.17__ JavaScript基础_1__第十二天

    Javascript基础 首先说声抱歉. 今日涉及内容难易度不统一,所以很多比較基础的属性直接通过思维导图展示了. 同一时候须要注意,今日思维导图中的内容和笔记中并非一一相应的,请读者自行对比查看. ...

  10. XCode下Swift – WebView IOS demo

    简介 我今天用Mac升级了XCode到8.1,Swift版本应该到了swift3,按网上的demo写webview的例子,报一堆错,整了一天才搞定,不想其他人踩坑了! XCode8.1 ,swift3 ...