2024年5月29日18:05:44
commit
d6bacf3452
|
|
@ -0,0 +1,92 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"zinx/ziface"
|
||||
)
|
||||
|
||||
/**
|
||||
存储有关zinx 框架的全局参数 , 供其他模块使用
|
||||
参数可以通过 zinx.json 由用户配置
|
||||
*/
|
||||
|
||||
type GlobalObj struct {
|
||||
|
||||
/**
|
||||
Server
|
||||
*/
|
||||
TcpServer ziface.IServer //当前zinx 全局的server 对象
|
||||
Host string //当前服务器监听的ip
|
||||
TcpPort int //当前服务器监听的端口
|
||||
Name string //当前服务的名称
|
||||
|
||||
/**
|
||||
zinx
|
||||
*/
|
||||
Version string //当前zinx 的版本号
|
||||
MaxConn int //当前服务器允许的最大连接数
|
||||
MaxPackageSize uint32 //当前zinx 框架数据包的最大值
|
||||
WokePoolSize uint32 //当前业务工作worker 池的goroutine 数量
|
||||
MaxWorkerTaskLen uint32 // zinx 框架最多允许用户开辟多少个worker (限定条件)
|
||||
}
|
||||
|
||||
/*
|
||||
GlobalObject 定义一个全局对外的globalobj 对象
|
||||
*/
|
||||
var GlobalObject *GlobalObj
|
||||
|
||||
/*
|
||||
提供一个init方法, 初始化 GlobalObject
|
||||
*/
|
||||
|
||||
func init() {
|
||||
|
||||
//默认配置
|
||||
GlobalObject = &GlobalObj{
|
||||
Name: "ZinxServer",
|
||||
Host: "0.0.0.0",
|
||||
Version: "V0.4",
|
||||
TcpPort: 8999,
|
||||
MaxConn: 1000,
|
||||
MaxPackageSize: 4096,
|
||||
WokePoolSize: 10,
|
||||
MaxWorkerTaskLen: 1024,
|
||||
}
|
||||
|
||||
//尝试从配置文件加载 config/zinx.json
|
||||
GlobalObject.Reload()
|
||||
}
|
||||
|
||||
/*
|
||||
Reload 从config/zinx.json 中加载用户配置
|
||||
*/
|
||||
func (g *GlobalObj) Reload() {
|
||||
data, err := os.ReadFile("conf/zinx.json")
|
||||
if err != nil {
|
||||
fmt.Println("conf/zinx.json 读取错误!")
|
||||
panic(err)
|
||||
}
|
||||
err = json.Unmarshal(data, &GlobalObject)
|
||||
if err != nil {
|
||||
fmt.Println("conf/zinx.json 解析错误!")
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// 打开 JSON 文件
|
||||
//file, err := os.Open("conf/zinx.json")
|
||||
//if err != nil {
|
||||
// fmt.Println(err)
|
||||
// return
|
||||
//}
|
||||
//defer file.Close()
|
||||
//// 解码 JSON 数据
|
||||
//decoder := json.NewDecoder(file)
|
||||
//err = decoder.Decode(&GlobalObject)
|
||||
//if err != nil {
|
||||
// fmt.Println(err)
|
||||
// return
|
||||
//}
|
||||
//fmt.Println(GlobalObject)
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package ziface
|
||||
|
||||
/*
|
||||
IConnManager 连接管理模块抽象层
|
||||
*/
|
||||
type IConnManager interface {
|
||||
|
||||
//添加连接
|
||||
Add(conn IConnection)
|
||||
|
||||
//删除连接
|
||||
Remove(conn IConnection)
|
||||
|
||||
//根据connID 获取连接
|
||||
|
||||
Get(connID uint32) (IConnection, error)
|
||||
//得到当前的连接总数
|
||||
Len() int
|
||||
|
||||
//清楚或终止所有连接
|
||||
ClearConn()
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package ziface
|
||||
|
||||
import "net"
|
||||
|
||||
// IConnection 定义链接的抽象层
|
||||
type IConnection interface {
|
||||
|
||||
// Start 启动链接
|
||||
Start()
|
||||
|
||||
// Stop 关闭连接
|
||||
Stop()
|
||||
|
||||
// GetTcpConnection 获取当前链接绑定的socket
|
||||
GetTcpConnection() *net.TCPConn
|
||||
|
||||
// GetConnectionID 获取当前链接模块的ID
|
||||
GetConnectionID() uint32
|
||||
|
||||
// RemoteAddr 获取远程客户点的tcp 状态 ip port
|
||||
RemoteAddr() net.Addr
|
||||
|
||||
// SendMsg 发送数据,将数据发送给远程客户端
|
||||
SendMsg(msgId uint32, data []byte) error
|
||||
|
||||
//设置连接属性
|
||||
SetProperty(key string, value interface{})
|
||||
|
||||
//获取连接属性
|
||||
GetProperty(key string) (interface{}, error)
|
||||
|
||||
//移除连接属性
|
||||
RemoveProperty(key string)
|
||||
}
|
||||
|
||||
// 定义一个处理链接的方法
|
||||
type HandleFunc func(*net.TCPConn, []byte, int) error
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package ziface
|
||||
|
||||
/*
|
||||
IDataPack
|
||||
封包,拆包
|
||||
直接面向tcp中的流,用于处理tcp 粘包问题
|
||||
*/
|
||||
type IDataPack interface {
|
||||
|
||||
//获取包的头长度方法
|
||||
GetHeadLen() uint32
|
||||
|
||||
//封包方法
|
||||
Pack(msg IMessage) ([]byte, error)
|
||||
|
||||
//拆包方法
|
||||
UnPack([]byte) (IMessage, error)
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package ziface
|
||||
|
||||
/*
|
||||
*
|
||||
将消息封装到message 中,定义抽象接口
|
||||
*/
|
||||
type IMessage interface {
|
||||
|
||||
//获取消息的id
|
||||
GetMsgId() uint32
|
||||
//获取消息的长度
|
||||
GetDataLen() uint32
|
||||
//获取消息的内容
|
||||
GetData() []byte
|
||||
|
||||
//设置消息的id
|
||||
SetMsgId(uint32)
|
||||
//设置消息的长度
|
||||
SetDataLen(uint32)
|
||||
//设置消息的内容
|
||||
SetData([]byte)
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package ziface
|
||||
|
||||
/*
|
||||
*
|
||||
消息管理层抽象
|
||||
*/
|
||||
type IMsgHandler interface {
|
||||
|
||||
//调度/执行队形router 消息处理方法
|
||||
DoMsgHandler(request IRequest)
|
||||
|
||||
//为消息添加具体的处理模块
|
||||
AddRouter(msgId uint32, router IRouter)
|
||||
|
||||
//启动work 工作池
|
||||
StartWorkPool()
|
||||
|
||||
//启动一个worker 工作流程
|
||||
//StartOneWorker(workerId int, taskQueue chan IRequest)
|
||||
|
||||
SendMsgTaskQueue(request IRequest)
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package ziface
|
||||
|
||||
/**
|
||||
封装客户端请求的链接信息
|
||||
*/
|
||||
|
||||
type IRequest interface {
|
||||
//获取连接
|
||||
GetConnection() IConnection
|
||||
|
||||
//请求的消息数据
|
||||
GetData() []byte
|
||||
|
||||
//获取请求消息的id
|
||||
GetMsgId() uint32
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package ziface
|
||||
|
||||
/**
|
||||
路由抽象接口
|
||||
路由里的接口都是IRequest
|
||||
*/
|
||||
|
||||
type IRouter interface {
|
||||
//在处理conn 业务之前的钩子方法 hook
|
||||
PreHandle(request IRequest)
|
||||
|
||||
//在处理conn 业务的主方法hook
|
||||
Handle(request IRequest)
|
||||
|
||||
//在处理conn业务之后的钩子方法
|
||||
PostHandle(request IRequest)
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package ziface
|
||||
|
||||
// 定义一个服务器接口
|
||||
type IServer interface {
|
||||
|
||||
//启动服务器
|
||||
Start()
|
||||
|
||||
//停止服务器
|
||||
Stop()
|
||||
|
||||
//运行服务器
|
||||
Serve()
|
||||
|
||||
//路由功能:给当前服务注册一个路由业务方法,供客户端链接处理使用
|
||||
AddRouter(msgId uint32, router IRouter)
|
||||
|
||||
//获取当前server 的连接管理器
|
||||
GetConnMgr() IConnManager
|
||||
|
||||
//注册OnConnStat 钩子函数方法
|
||||
SetOnConnStart(func(connection IConnection))
|
||||
|
||||
//注册OnConnStop 钩子函数方法
|
||||
SetOnConnStop(func(connection IConnection))
|
||||
|
||||
//调用OnConnStat 钩子函数方法
|
||||
CallOnConnStart(connection IConnection)
|
||||
|
||||
//调用OnConnStop 钩子函数方法
|
||||
CallOnConnStop(connection IConnection)
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
package znet
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"zinx/ziface"
|
||||
)
|
||||
|
||||
/*
|
||||
连接管理模块
|
||||
*/
|
||||
|
||||
type ConnManager struct {
|
||||
|
||||
//管理的连接集合
|
||||
connections map[uint32]ziface.IConnection
|
||||
|
||||
//保护连接集合的读写锁
|
||||
connLock sync.RWMutex
|
||||
}
|
||||
|
||||
// NewConnManager 创建当前连接的方法
|
||||
func NewConnManager() *ConnManager {
|
||||
return &ConnManager{
|
||||
connections: make(map[uint32]ziface.IConnection),
|
||||
}
|
||||
}
|
||||
|
||||
// Add 添加连接
|
||||
func (connMgr *ConnManager) Add(conn ziface.IConnection) {
|
||||
//保护共享资源map ,加写锁
|
||||
connMgr.connLock.Lock()
|
||||
defer connMgr.connLock.Unlock()
|
||||
|
||||
//将conn 加入到connmanager 中
|
||||
connMgr.connections[conn.GetConnectionID()] = conn
|
||||
|
||||
fmt.Println("connID = ", conn.GetConnectionID(), "add connection add to connmanager successfully : conn num = ", connMgr.Len())
|
||||
}
|
||||
|
||||
// Remove 删除连接
|
||||
func (connMgr *ConnManager) Remove(conn ziface.IConnection) {
|
||||
//保护共享资源map ,加写锁
|
||||
connMgr.connLock.Lock()
|
||||
defer connMgr.connLock.Unlock()
|
||||
|
||||
//删除链接
|
||||
delete(connMgr.connections, conn.GetConnectionID())
|
||||
fmt.Println("connID = ", conn.GetConnectionID(), "delete connection from connmanager successfully : conn num = ", connMgr.Len())
|
||||
}
|
||||
|
||||
// 根据connID 获取连接
|
||||
func (connMgr *ConnManager) Get(connID uint32) (ziface.IConnection, error) {
|
||||
//保护共享资源map ,加写锁
|
||||
connMgr.connLock.RLock()
|
||||
defer connMgr.connLock.RUnlock()
|
||||
|
||||
if conn, ok := connMgr.connections[connID]; ok {
|
||||
//找到了
|
||||
return conn, nil
|
||||
} else {
|
||||
return nil, errors.New("connection is not found ")
|
||||
}
|
||||
}
|
||||
|
||||
// 得到当前的连接总数
|
||||
func (connMgr *ConnManager) Len() int {
|
||||
return len(connMgr.connections)
|
||||
}
|
||||
|
||||
// 清楚或终止所有连接
|
||||
func (connMgr *ConnManager) ClearConn() {
|
||||
//保护共享资源map ,加写锁
|
||||
connMgr.connLock.Lock()
|
||||
defer connMgr.connLock.Unlock()
|
||||
|
||||
//删除conn 饼停止conn 的工作
|
||||
for connID, conn := range connMgr.connections {
|
||||
//停止
|
||||
conn.Stop()
|
||||
//删除
|
||||
delete(connMgr.connections, connID)
|
||||
}
|
||||
|
||||
fmt.Println("clear all connection successfully ! conn num = ", connMgr.Len())
|
||||
}
|
||||
|
|
@ -0,0 +1,260 @@
|
|||
package znet
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"zinx/utils"
|
||||
"zinx/ziface"
|
||||
)
|
||||
|
||||
// Connection 链接模块
|
||||
type Connection struct {
|
||||
|
||||
//当前连接隶属于那个server
|
||||
TcpServer ziface.IServer
|
||||
|
||||
//当前链接的socket tcp 套接字
|
||||
Conn *net.TCPConn
|
||||
|
||||
//链接的id
|
||||
ConnID uint32
|
||||
|
||||
//当前链接的状态
|
||||
isClosed bool
|
||||
|
||||
////当前链接锁绑定的处理业务的api
|
||||
//handleApi ziface.HandleFunc
|
||||
|
||||
//告知当前链接的退出/停止 (由reading 告诉 writering 退出)
|
||||
ExitChan chan bool
|
||||
|
||||
//无缓冲的管道,用于读写goroutine之间的 消息通信
|
||||
msgChan chan []byte
|
||||
|
||||
//消息处理的msgId 处理业务对应的api
|
||||
MsgHandler ziface.IMsgHandler
|
||||
|
||||
//连接属性集合
|
||||
property map[string]interface{}
|
||||
|
||||
//保护连接属性的锁
|
||||
propertyLock sync.RWMutex
|
||||
}
|
||||
|
||||
// NewConnection 初始化链接
|
||||
func NewConnection(server ziface.IServer, conn *net.TCPConn, connID uint32, handler ziface.IMsgHandler) *Connection {
|
||||
c := &Connection{
|
||||
TcpServer: server,
|
||||
Conn: conn,
|
||||
ConnID: connID,
|
||||
isClosed: false,
|
||||
MsgHandler: handler,
|
||||
msgChan: make(chan []byte),
|
||||
ExitChan: make(chan bool, 1),
|
||||
property: make(map[string]interface{}),
|
||||
}
|
||||
|
||||
//将conn 加入到 connManager 中
|
||||
c.TcpServer.GetConnMgr().Add(c)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Connection) StartReader() {
|
||||
fmt.Println("reading goroutine is running ...")
|
||||
defer fmt.Println("connID = ", c.ConnID, " reading is exit , remote addr is =", c.Conn.RemoteAddr().String())
|
||||
defer c.Stop()
|
||||
|
||||
for {
|
||||
//读取数据
|
||||
//buf := make([]byte, utils.GlobalObject.MaxPackageSize)
|
||||
//
|
||||
//_, err := c.Conn.Read(buf)
|
||||
//if err != nil {
|
||||
// fmt.Println("conn read err")
|
||||
// continue
|
||||
//}
|
||||
|
||||
//创建一个拆包解包对象
|
||||
dp := NewDataPack()
|
||||
|
||||
//读取客户端的8个字节
|
||||
headData := make([]byte, dp.GetHeadLen())
|
||||
|
||||
//拆包得到msgId 和 msgDataLen
|
||||
if _, err := io.ReadFull(c.GetTcpConnection(), headData); err != nil {
|
||||
fmt.Println("read msg head error", err)
|
||||
break
|
||||
}
|
||||
|
||||
msg, err := dp.UnPack(headData)
|
||||
if err != nil {
|
||||
fmt.Println("UnPack error", err)
|
||||
break
|
||||
}
|
||||
var data []byte
|
||||
if msg.GetDataLen() > 0 {
|
||||
data = make([]byte, msg.GetDataLen())
|
||||
if _, err := io.ReadFull(c.GetTcpConnection(), data); err != nil {
|
||||
fmt.Println("read msg data error", err)
|
||||
}
|
||||
}
|
||||
|
||||
msg.SetData(data)
|
||||
|
||||
//调用链接处理的api
|
||||
//if err = c.handleApi(c.Conn, buf, len); err != nil {
|
||||
// fmt.Println("connID = ", c.ConnID, "handle is err = ", err)
|
||||
//}
|
||||
|
||||
//的到当前conn 数据的request 请求数据
|
||||
req := Request{
|
||||
conn: c,
|
||||
msg: msg,
|
||||
}
|
||||
|
||||
//go func(request ziface.IRequest) {
|
||||
// //从路由中,找到注册绑定的conn对应的router 调用
|
||||
// c.Router.PreHandle(request)
|
||||
// c.Router.Handle(request)
|
||||
// c.Router.PostHandle(request)
|
||||
//}(&req)
|
||||
|
||||
if utils.GlobalObject.WokePoolSize > 0 {
|
||||
//已经开启工作池,将消息发给工作池
|
||||
c.MsgHandler.SendMsgTaskQueue(&req)
|
||||
} else {
|
||||
//根据绑定msgID找到对应处理api业务执行
|
||||
go c.MsgHandler.DoMsgHandler(&req)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// StartWriter写消息 goroutine, 专门发送给客户端消息的模块
|
||||
func (c *Connection) StartWriter() {
|
||||
fmt.Println("[Writer GoRoutine is Running...]")
|
||||
|
||||
defer fmt.Println(c.RemoteAddr().String(), " conn writering exit")
|
||||
|
||||
//不断阻塞的等待channel的消息
|
||||
for {
|
||||
select {
|
||||
case data := <-c.msgChan:
|
||||
if _, err := c.Conn.Write(data); err != nil {
|
||||
fmt.Println("send data error ", err)
|
||||
return
|
||||
}
|
||||
case <-c.ExitChan:
|
||||
//代表已经退出,writer 也要退出
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start 启动链接
|
||||
func (c *Connection) Start() {
|
||||
fmt.Println("conn start() ...conn:", c.ConnID)
|
||||
//处理业务数据
|
||||
go c.StartReader()
|
||||
go c.StartWriter()
|
||||
|
||||
//按照开发者传递进来的 创建连接之后需要调用的处理业务对应执行hook 函数
|
||||
c.TcpServer.CallOnConnStart(c)
|
||||
}
|
||||
|
||||
// Stop 关闭连接
|
||||
func (c *Connection) Stop() {
|
||||
fmt.Println("conn stop .....,connID:", c.ConnID)
|
||||
|
||||
if c.isClosed == true {
|
||||
return
|
||||
}
|
||||
c.isClosed = true
|
||||
|
||||
//调用开发者注册销毁连接之前执行的hook 函数
|
||||
c.TcpServer.CallOnConnStop(c)
|
||||
|
||||
//关闭连接
|
||||
c.Conn.Close()
|
||||
|
||||
//告知writer 关闭
|
||||
c.ExitChan <- true
|
||||
|
||||
//将conn 删除掉
|
||||
c.TcpServer.GetConnMgr().Remove(c)
|
||||
|
||||
//关闭资源
|
||||
close(c.ExitChan)
|
||||
close(c.msgChan)
|
||||
}
|
||||
|
||||
// GetTcpConnection 获取当前链接绑定的socket
|
||||
func (c *Connection) GetTcpConnection() *net.TCPConn {
|
||||
return c.Conn
|
||||
}
|
||||
|
||||
// GetConnectionID 获取当前链接模块的ID
|
||||
func (c *Connection) GetConnectionID() uint32 {
|
||||
return c.ConnID
|
||||
}
|
||||
|
||||
// RemoteAddr 获取远程客户点的tcp 状态 ip port
|
||||
func (c *Connection) RemoteAddr() net.Addr {
|
||||
return c.Conn.RemoteAddr()
|
||||
}
|
||||
|
||||
// Send 发送数据,将数据发送给远程客户端,先封包在发送
|
||||
func (c *Connection) SendMsg(msgId uint32, data []byte) error {
|
||||
|
||||
if c.isClosed == true {
|
||||
return errors.New("connection close when send msg")
|
||||
}
|
||||
//将data 在封包
|
||||
dp := NewDataPack()
|
||||
binaryMsg, err := dp.Pack(NewMessage(msgId, data))
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("pack msg id = ", msgId)
|
||||
return errors.New("pack err msg")
|
||||
}
|
||||
|
||||
//将数据发送到客户端
|
||||
//if _, err := c.Conn.Write(binaryMsg); err != nil {
|
||||
// fmt.Println("write msg id = ", msgId)
|
||||
// return errors.New("write msg err")
|
||||
//}
|
||||
c.msgChan <- binaryMsg
|
||||
return nil
|
||||
}
|
||||
|
||||
// 设置连接属性
|
||||
func (c *Connection) SetProperty(key string, value interface{}) {
|
||||
c.propertyLock.Lock()
|
||||
defer c.propertyLock.Unlock()
|
||||
|
||||
//添加一个连接属性
|
||||
c.property[key] = value
|
||||
}
|
||||
|
||||
// 获取连接属性
|
||||
func (c *Connection) GetProperty(key string) (interface{}, error) {
|
||||
c.propertyLock.RLock()
|
||||
defer c.propertyLock.RUnlock()
|
||||
|
||||
if value, ok := c.property[key]; ok {
|
||||
return value, nil
|
||||
} else {
|
||||
return nil, errors.New("not property found")
|
||||
}
|
||||
}
|
||||
|
||||
// 移除连接属性
|
||||
func (c *Connection) RemoveProperty(key string) {
|
||||
c.propertyLock.Lock()
|
||||
defer c.propertyLock.Unlock()
|
||||
|
||||
//删除
|
||||
delete(c.property, key)
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
package znet
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"zinx/utils"
|
||||
"zinx/ziface"
|
||||
)
|
||||
|
||||
/**
|
||||
封包拆包的具体模块
|
||||
*/
|
||||
|
||||
type DataPack struct {
|
||||
}
|
||||
|
||||
// 初始化示例
|
||||
func NewDataPack() *DataPack {
|
||||
return &DataPack{}
|
||||
}
|
||||
|
||||
// 获取包的头长度方法
|
||||
func (d *DataPack) GetHeadLen() uint32 {
|
||||
|
||||
//datalen uint32(4个字节) +id (4个字节)
|
||||
return 8
|
||||
}
|
||||
|
||||
// 封包方法
|
||||
func (d *DataPack) Pack(msg ziface.IMessage) ([]byte, error) {
|
||||
//创建bytes字节缓冲
|
||||
dataBuf := bytes.NewBuffer([]byte{})
|
||||
//将datalen 写入buf
|
||||
if err := binary.Write(dataBuf, binary.LittleEndian, msg.GetDataLen()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//将msgid写入buf
|
||||
if err := binary.Write(dataBuf, binary.LittleEndian, msg.GetMsgId()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//将data写入buf
|
||||
if err := binary.Write(dataBuf, binary.LittleEndian, msg.GetData()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dataBuf.Bytes(), nil
|
||||
}
|
||||
|
||||
// 拆包方法 先读head 长度 ,根据head 长度读取内容
|
||||
func (d *DataPack) UnPack(binaryData []byte) (ziface.IMessage, error) {
|
||||
//创建bytes字节缓冲
|
||||
dataBuf := bytes.NewReader(binaryData)
|
||||
|
||||
//直解压 head 获取datalen 与 msgid
|
||||
msg := &Message{}
|
||||
|
||||
//读取datalen
|
||||
if err := binary.Read(dataBuf, binary.LittleEndian, &msg.DataLen); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//读取msgId
|
||||
if err := binary.Read(dataBuf, binary.LittleEndian, &msg.Id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//判断datalen是否超出最大包的限制
|
||||
if utils.GlobalObject.MaxPackageSize > 0 && msg.DataLen > utils.GlobalObject.MaxPackageSize {
|
||||
return nil, errors.New("too large data recv")
|
||||
}
|
||||
|
||||
return msg, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package znet
|
||||
|
||||
type Message struct {
|
||||
|
||||
//消息的id
|
||||
Id uint32
|
||||
//消息的内容的长度
|
||||
DataLen uint32
|
||||
//消息的内容
|
||||
Data []byte
|
||||
}
|
||||
|
||||
func NewMessage(id uint32, data []byte) *Message {
|
||||
return &Message{
|
||||
Id: id,
|
||||
Data: data,
|
||||
DataLen: uint32(len(data)),
|
||||
}
|
||||
}
|
||||
|
||||
// GetMsgId 获取消息的id
|
||||
func (m *Message) GetMsgId() uint32 {
|
||||
return m.Id
|
||||
}
|
||||
|
||||
// GetDataLen 获取消息的长度
|
||||
func (m *Message) GetDataLen() uint32 {
|
||||
return m.DataLen
|
||||
}
|
||||
|
||||
// GetData 获取消息的内容
|
||||
func (m *Message) GetData() []byte {
|
||||
return m.Data
|
||||
}
|
||||
|
||||
// SetMsgId 设置消息的id
|
||||
func (m *Message) SetMsgId(id uint32) {
|
||||
m.Id = id
|
||||
}
|
||||
|
||||
// SetDataLen 设置消息的长度
|
||||
func (m *Message) SetDataLen(dataLen uint32) {
|
||||
m.DataLen = dataLen
|
||||
}
|
||||
|
||||
// SetData 设置消息的内容
|
||||
func (m *Message) SetData(data []byte) {
|
||||
m.Data = data
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
package znet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"zinx/utils"
|
||||
"zinx/ziface"
|
||||
)
|
||||
|
||||
/**
|
||||
消息模块的实现层
|
||||
*/
|
||||
|
||||
type MsgHandler struct {
|
||||
|
||||
//存放每个msgId 对应的处理方法
|
||||
Apis map[uint32]ziface.IRouter
|
||||
|
||||
//负责worker 取任务的消息对列
|
||||
TaskQueue []chan ziface.IRequest
|
||||
|
||||
//业务工作池的数量
|
||||
WorkPoolSize uint32
|
||||
}
|
||||
|
||||
// 添加初始化方法
|
||||
func NewMsgHandler() *MsgHandler {
|
||||
return &MsgHandler{
|
||||
Apis: make(map[uint32]ziface.IRouter),
|
||||
WorkPoolSize: utils.GlobalObject.WokePoolSize,
|
||||
TaskQueue: make([]chan ziface.IRequest, utils.GlobalObject.WokePoolSize),
|
||||
}
|
||||
}
|
||||
|
||||
// 调度/执行队形router 消息处理方法
|
||||
func (msgHandler *MsgHandler) DoMsgHandler(request ziface.IRequest) {
|
||||
//request 获取msgId
|
||||
router, ok := msgHandler.Apis[request.GetMsgId()]
|
||||
if !ok {
|
||||
fmt.Println("api msg id = ", request.GetMsgId(), " is not found , need register")
|
||||
return
|
||||
}
|
||||
//根据路由调用对应的业务
|
||||
router.PreHandle(request)
|
||||
router.Handle(request)
|
||||
router.PostHandle(request)
|
||||
}
|
||||
|
||||
// 为消息添加具体的处理模块
|
||||
func (msgHandler *MsgHandler) AddRouter(msgId uint32, router ziface.IRouter) {
|
||||
//判断msg 绑定的api 是否存在
|
||||
if _, ok := msgHandler.Apis[msgId]; ok {
|
||||
//id已经注册过
|
||||
panic("repeat api , msgId = " + strconv.Itoa(int(msgId)))
|
||||
}
|
||||
|
||||
//添加对应关系
|
||||
msgHandler.Apis[msgId] = router
|
||||
fmt.Println("add api msgid = ", msgId, " successful")
|
||||
}
|
||||
|
||||
// StartWorkPool 启动一个worker 工作池,(开启工作池只能发生一次,一个zinx 框架只能有一个工作池)
|
||||
func (msgHandler *MsgHandler) StartWorkPool() {
|
||||
|
||||
//根据workpoolsize分别开启worker,每个worker 用一个go 承载
|
||||
for i := 0; i < int(msgHandler.WorkPoolSize); i++ {
|
||||
|
||||
//1.当前worker对应channel 的消息队列 , 开启空间 , 第0个worker 对应 第0 个channel..
|
||||
msgHandler.TaskQueue[i] = make(chan ziface.IRequest, utils.GlobalObject.MaxWorkerTaskLen)
|
||||
|
||||
fmt.Println("i = ", i, "taskQueue = ", msgHandler.TaskQueue[i])
|
||||
|
||||
//启动当前worker,阻塞等待消息从channel中传递过来
|
||||
go msgHandler.StartOneWorker(i, msgHandler.TaskQueue[i])
|
||||
}
|
||||
}
|
||||
|
||||
// StartOneWorker 启动一个worker 工作流程
|
||||
func (msgHandler *MsgHandler) StartOneWorker(workerId int, taskQueue chan ziface.IRequest) {
|
||||
fmt.Println("Worker ID = ", workerId, " is starting ...")
|
||||
|
||||
//不断阻塞等待消息
|
||||
for {
|
||||
select {
|
||||
case request := <-taskQueue:
|
||||
msgHandler.DoMsgHandler(request)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 将消息交给taskQueue, 由worker 处理
|
||||
func (msgHander *MsgHandler) SendMsgTaskQueue(request ziface.IRequest) {
|
||||
//将消息平均分配 给worker(根据ConnectionID 进行分配)
|
||||
workerID := request.GetConnection().GetConnectionID() % msgHander.WorkPoolSize
|
||||
fmt.Println("add connID = ", request.GetConnection().GetConnectionID(), " request MsgId = ", request.GetMsgId(), " to worker id =", workerID)
|
||||
//将消息发送给对应worker的taskQUeue即可
|
||||
msgHander.TaskQueue[workerID] <- request
|
||||
fmt.Println("msgHander.TaskQueue[workerID] = ", workerID)
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package znet
|
||||
|
||||
import "zinx/ziface"
|
||||
|
||||
type Request struct {
|
||||
|
||||
//客户端链接
|
||||
conn ziface.IConnection
|
||||
|
||||
//客户端的请求数据
|
||||
msg ziface.IMessage
|
||||
}
|
||||
|
||||
// GetConnection 获取连接
|
||||
func (r *Request) GetConnection() ziface.IConnection {
|
||||
return r.conn
|
||||
}
|
||||
|
||||
// GetData 请求的消息数据
|
||||
func (r *Request) GetData() []byte {
|
||||
return r.msg.GetData()
|
||||
}
|
||||
|
||||
// 获取请求消息的id
|
||||
func (r *Request) GetMsgId() uint32 {
|
||||
return r.msg.GetMsgId()
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package znet
|
||||
|
||||
import "zinx/ziface"
|
||||
|
||||
type BaseRouter struct {
|
||||
}
|
||||
|
||||
// PreHandle 在处理conn 业务之前的钩子方法 hook
|
||||
func (br *BaseRouter) PreHandle(request ziface.IRequest) {
|
||||
|
||||
}
|
||||
|
||||
// Handle 在处理conn 业务的主方法hook
|
||||
func (br *BaseRouter) Handle(request ziface.IRequest) {
|
||||
|
||||
}
|
||||
|
||||
// PostHandle 在处理conn业务之后的钩子方法
|
||||
func (br *BaseRouter) PostHandle(request ziface.IRequest) {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
package znet
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"zinx/utils"
|
||||
"zinx/ziface"
|
||||
)
|
||||
|
||||
// Server /*
|
||||
/**
|
||||
IServer 的接口实现,定义一个Serve 的服务器模块
|
||||
*/
|
||||
type Server struct {
|
||||
|
||||
//服务器名称
|
||||
Name string
|
||||
|
||||
//服务器绑定的ip版本
|
||||
IPVersion string
|
||||
|
||||
//服务器监听的ip地址
|
||||
IP string
|
||||
|
||||
//f服务器监听的端口
|
||||
Port int
|
||||
|
||||
//当前Server由用户绑定的回调router,也就是Server注册的链接对应的处理业务
|
||||
MsgHandler ziface.IMsgHandler
|
||||
|
||||
//该server 的连接管理器
|
||||
ConnMgr ziface.IConnManager
|
||||
|
||||
//该server创建之后自动调用的hook 函数 -- OnConnStart
|
||||
OnConnStart func(conn ziface.IConnection)
|
||||
|
||||
//该server销毁连接之前自动调用的hook 函数 -- OnConnStop
|
||||
OnConnStop func(conn ziface.IConnection)
|
||||
}
|
||||
|
||||
//实现IServer 接口
|
||||
|
||||
func (s *Server) Start() {
|
||||
fmt.Printf("[Zinx GlobalObject] Server Name : %s,Ip : %s,Port : %d\n",
|
||||
utils.GlobalObject.Name, utils.GlobalObject.Host, utils.GlobalObject.TcpPort)
|
||||
fmt.Printf("[Zinx GlobalObject] Version Name : %s,MaxConn : %d,MaxPackageSize : %d\n",
|
||||
utils.GlobalObject.Version, utils.GlobalObject.MaxConn, utils.GlobalObject.MaxPackageSize)
|
||||
fmt.Printf("[Start] Server Listenner at Ip :%s ,Port %d, is startring \n", s.IP, s.Port)
|
||||
go func() {
|
||||
|
||||
//开启worker 消息队列几工作池
|
||||
s.MsgHandler.StartWorkPool()
|
||||
|
||||
//1.获取tcp地址
|
||||
addr, err := net.ResolveTCPAddr(s.IPVersion, fmt.Sprintf("%s:%d", s.IP, s.Port))
|
||||
if err != nil {
|
||||
fmt.Println("resplve tcp addr error :", err)
|
||||
}
|
||||
|
||||
//2.监听服务器地址
|
||||
listenner, err := net.ListenTCP(s.IPVersion, addr)
|
||||
if err != nil {
|
||||
fmt.Println("listen ", s.IPVersion, " error", err)
|
||||
}
|
||||
fmt.Println("start zinx server ", s.Name, "successful listenning")
|
||||
|
||||
//3.阻塞等待客户端链接,处理客户端连接请求
|
||||
|
||||
var cid uint32
|
||||
cid = 0
|
||||
for {
|
||||
//如果有客户端连接,阻塞返回
|
||||
conn, err := listenner.AcceptTCP()
|
||||
if err != nil {
|
||||
fmt.Println("accept error", err)
|
||||
continue
|
||||
}
|
||||
////已经建立客户端连接,处理数据
|
||||
//go func() {
|
||||
// for {
|
||||
// buf := make([]byte, 512)
|
||||
// len, err2 := conn.Read(buf)
|
||||
// if err2 != nil {
|
||||
// fmt.Println("recv buf error", err)
|
||||
// continue
|
||||
// }
|
||||
//
|
||||
// fmt.Printf("recv buf:%s,len:%d\n", string(buf[:len]), len)
|
||||
// //回显功能
|
||||
// if _, err := conn.Write(buf[:len]); err != nil {
|
||||
// fmt.Println("write back buf error ", err)
|
||||
// continue
|
||||
// }
|
||||
// }
|
||||
//}()
|
||||
|
||||
//设置最大连接个数判断,如果超过最大连接,那么关闭次新的连接
|
||||
if s.ConnMgr.Len() >= utils.GlobalObject.MaxConn {
|
||||
|
||||
//todo 给客户端响应超出最大连接数,错误包
|
||||
fmt.Println("Too Many Connections MaxConn = ", utils.GlobalObject.MaxConn)
|
||||
conn.Close()
|
||||
continue
|
||||
}
|
||||
|
||||
//处理新连接的业务和方法与conn 进行绑定 的到链接模块
|
||||
dealConn := NewConnection(s, conn, cid, s.MsgHandler)
|
||||
cid++
|
||||
go dealConn.Start()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func CallBackToClient(conn *net.TCPConn, data []byte, cnt int) error {
|
||||
//回显业务
|
||||
fmt.Println("[Conn Handle] CallBackToClient ... ")
|
||||
if _, err := conn.Write(data[:cnt]); err != nil {
|
||||
fmt.Println("write back buf err ", err)
|
||||
return errors.New("CallBackToClient error")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) Stop() {
|
||||
//将服务的资源,状态,链接信息进行停止,或回收
|
||||
|
||||
fmt.Println("[Stop] zinx Server name = ", s.Name)
|
||||
s.ConnMgr.ClearConn()
|
||||
}
|
||||
|
||||
func (s *Server) Serve() {
|
||||
//启动server
|
||||
s.Start()
|
||||
|
||||
//TODO 启动服务之后一些扩展业务
|
||||
|
||||
//阻塞
|
||||
select {}
|
||||
}
|
||||
|
||||
func (s *Server) AddRouter(msgId uint32, router ziface.IRouter) {
|
||||
s.MsgHandler.AddRouter(msgId, router)
|
||||
fmt.Println("add router successful")
|
||||
}
|
||||
|
||||
// NewServer 初始化serve
|
||||
func NewServer() ziface.IServer {
|
||||
s := &Server{
|
||||
Name: utils.GlobalObject.Name,
|
||||
IPVersion: "tcp4",
|
||||
IP: utils.GlobalObject.Host,
|
||||
Port: utils.GlobalObject.TcpPort,
|
||||
MsgHandler: NewMsgHandler(),
|
||||
ConnMgr: NewConnManager(),
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Server) GetConnMgr() ziface.IConnManager {
|
||||
return s.ConnMgr
|
||||
}
|
||||
|
||||
// SetOnConnStart 注册OnConnStat 钩子函数方法
|
||||
func (s *Server) SetOnConnStart(hookFunc func(connection ziface.IConnection)) {
|
||||
s.OnConnStart = hookFunc
|
||||
}
|
||||
|
||||
// SetOnConnStop 注册OnConnStop 钩子函数方法
|
||||
func (s *Server) SetOnConnStop(hookFunc func(connection ziface.IConnection)) {
|
||||
s.OnConnStop = hookFunc
|
||||
}
|
||||
|
||||
// CallOnConnStart 调用OnConnStat 钩子函数方法
|
||||
func (s *Server) CallOnConnStart(conn ziface.IConnection) {
|
||||
if s.OnConnStart != nil {
|
||||
fmt.Println("-----> CallOnConnStart() ....")
|
||||
s.OnConnStart(conn)
|
||||
}
|
||||
}
|
||||
|
||||
// CallOnConnStop 调用OnConnStop 钩子函数方法
|
||||
func (s *Server) CallOnConnStop(conn ziface.IConnection) {
|
||||
if s.OnConnStop != nil {
|
||||
fmt.Println("-----> CallOnConnStop() ....")
|
||||
s.OnConnStop(conn)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue