- Tcp Server
- Tcp Connect
- Request Handle
- Push Handle
- Middleware
- Inversion of Control
- Examples
type TcpServer interface {
Listen(*Opt)
Accept(func(*TcpConn, *Middleware))
}
//创建 server
server := jaguar.NewServer()
//创建配置
opt := &jaguar.Opt{
Addr: "0.0.0.0:9000", //绑定地址和端口
PacketMaxLength: 6000, //收发最大包体字节,超过该字节主动断开连接。
PacketHeaderLength: 2, //包头占位长度 1,2,4,8
IdleCheckFrequency: time.Second * 120, //心跳检测
ByteOrder: binary.BigEndian //网络字节序
}
// 新连接回调
// conn : 新连接
// middleware : 中间件
server.Accept(func(conn *jaguar.TcpConn, middleware *jaguar.Middleware) {
//session 是一个自定义的插件
session := plugins.NewSession()
//conn 附加插件
conn.Attach(session)
//使用自定义的 session.CloseEvent 注册连接关闭事件
middleware.Closed(session.CloseEvent)
})
//开启监听
server.Listen(opt)
type TcpConn interface {
//附加插件对象,可以通过依赖注入获取 type Test struct {obj object `inject:""`}
Attach(object interface{})
//附加插件对象接口形式,可以通过依赖注入获取 type Test struct {obj inteface `inject:"impl"`}
AttachImpl(impl string, object interface{})
//关闭连接
Close()
//获取远程地址
RemoteAddr() net.Addr
//推送 推送处理器
Push(pushHandle Encode) error
}
// 请求处理器,读写io数据和返回响应,继承该接口可使用。
type ReqHandle interface {
//读取流数据
ReadStream(...interface{}) error
//读取流数据中的字符串
ReadStreamByString(int, *string) error
//写入流数据
WriteStream(...interface{})
//回执响应
Respone() error
}
func init() {
// 注册请求处理器 对应请求数据包的协议id 101
// 请求处理器chat必须实现 Execute 方法
jaguar.AddRequest(101, new(chat))
}
//定义一个聊天请求处理器
type chat struct {
//继承 ReqHandle
jaguar.ReqHandle `inject:"req_handle"`
//通过依赖注入获取插件-实体方式
Session *plugins.Session `inject:""`
//使用 jaguar.TcpConn 插件, 该插件负责连接相关
Conn jaguar.TcpConn `inject:"tcp_conn"`
}
// Execute - 必须实现
func (c *chat) Execute() {
//c.ReadStream()
//c.WriteStream()
//c.Respone()
}
// 推送处理器,写io数据,继承该接口可使用。
type PushHandle interface {
//Write byte stream data
WriteStream(values ...interface{})
}
// 定义个推送处理器
type chat struct {
jaguar.PushHandle `inject:"push_handle"`
//要推送的数据列 三项
sender string
content string
row uint32
}
// ProtocolId - 必须实现
func (c *chat) ProtocolId() uint16 {
//推送数据包的协议id
//jaguar.TcpConn 插件会调用 chat.ProtocolId()
return 300
}
// Encode() - 必须实现
func (c *chat) Encode() {
//jaguar.TcpConn 插件会调用 chat.Encode()
c.WriteStream(c.row)
c.WriteStream(uint8(len(c.sender)), c.sender)
c.WriteStream(uint16(len(c.content)), c.content)
}
TcpConn.Push(&chat{sender:"lucifer", content:"fuck"})
// 拦截器
server.Accept(func(conn jaguar.TcpConn, middleware *jaguar.Middleware) {
middleware.Closed(f func(){
// Closed - Close registration for callbacks
})
middleware.Recover(f func(e error,s string){
// Recover - Request a panic in the code
})
middleware.Reader(func(id uint16, b *bytes.Buffer) *bytes.Buffer {
// Reader - Read data
return b
})
middleware.Writer(func(id uint16, b *bytes.Buffer) *bytes.Buffer {
// Writer - Write data
return b
})
middleware.Request(func(id uint16, reqHandle interface{}) {
//Request - Callback at request
})
middleware.Respone(func(id uint16, reqHandle interface{}) {
//Respone - Callback when requesting a reply
})
middleware.Push(func(uint16, interface{}){
//Push - Callbacks on push
})
})
# 启动示例程序
$ cd jaguar/chat_examples
# 启动server
$ go run server/main.go
# 开启新窗口启动客户端 1
$ command + t
$ go run mock_client/main.go
# 开启新窗口启动客户端 2
$ command + t
$ go run mock_client/main.go
报文格式, 可变长数据需要指明 [长度, 数据]
+-------------------+--------------+---------------------------------------------------+
| 2 Bytes | 2 Bytes | N Bytes |
+-------------------+--------------+---------------------------------------------------+
|<= length of body =>| id | <======= data =======================>|
|<============= header ===========>|<==================== body =======================>|
协议 :请求登录
id : 100 (2 Bytes)
token :[] (1 Bytes, N Bytes)
协议 :请求登录回执
id : 100 (2 Bytes)
ok : 1 (1 Bytes)
uid : [](4 Bytes)
uname : [](1 Bytes, N Bytes)
协议 :请求聊天消息
id : 101 (2 Bytes)
row : [] (4 Bytes)
content : [](2 Bytes, N Bytes)
协议 :请求聊天消息回执
id : 101 (2 Bytes)
ok : 1 (1 Bytes)
协议 :聊天信息推送
id : 300 (2 Bytes)
sender : [] (1 Bytes, N Bytes)
content : [](2 Bytes, N Bytes)