tcpsrv

package
v1.4.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 30, 2020 License: MIT Imports: 12 Imported by: 0

README

TCP 服务

开箱即用的 TCP 服务

协议

心跳

心跳包为长度为 0 的空数据包,最长时间 30s 发一次,否则链接将会被断开

请求响应数据

请求和响应的数据必须按照该协议来

请求数据

{
  "cmd": "register",
  "seqno": "unique string",
  "data": {}
}
  • cmd 命令名称
  • seqno 请求标识符
  • data 请求数据

响应数据

{
  "cmd": "register",
  "seqno": "unique string",
  "msg": "ok",
  "status": 0,
  "data": {}
}
  • cmd 命令名称,原样返回
  • seqno 请求标识符,原样返回
  • msg 处理后的消息,如果消息是处理成功的,默认都是 ok
  • status 错误状态码,0 为成功,非 0 为失败
  • data 响应数据

使用

示例概览

服务器
package main

import (
  "github.com/go-eyas/toolkit/tcp"
  "github.com/go-eyas/toolkit/tcp/tcpsrv"
  "fmt"
)

func main() {
  server, err := tcpsrv.NewServerSrv(&tcp.Config{
    Network:":6700",

    // 自定义tcp数据包协议,实现下方两个方法即可
    // 将业务数据封装成tcp数据包
    // Packer: func(data []byte) ([]byte,  error) {}, 
    // 将 tcp 连接收到的数据包解析成业务数据,返回的业务数据必须符合上方定义的 json 数据
    // Parser: func(conn *tcp.Conn, pack []byte) ( [][]byte,  error) {}, 
  })
  if err != nil {
    panic(err)
  }
  
  // log 中间件
  server.Use(func(c *tcpsrv.Context) {
    fmt.Printf("TCP 收到 cmd=%s seqno=%s data=%s\n", c.CMD, c.Seqno, string(c.Payload))
    c.Next()
    fmt.Printf("TCP 响应 cmd=%s seqno=%s data=%s\n", c.CMD, c.Seqno, string(c.Response.Data))
  })

  // 验证中间件
  server.Use(func(c *tcpsrv.Context) {
    if c.CMD != "register" {
      _, ok := c.Get("uid").(int64)
      if !ok {
        c.Response.Msg = "permission defined"
        c.Response.Status = 401
        c.Abort() // 停止后面的中间件执行
        return
      } 
    }
    c.Next() // 如后续无操作,可省略
  })

  server.Handle("register", func(c *tcpsrv.Context) {
    body := &struct {
      UID int64 `json:"uid"`
    }{}
    err := c.Bind(body) // 绑定json数据
    if err != nil {
      panic(err) // 在 Handle panic 后不会导致程序异常,会响应错误数据到客户端
    }
    c.Set("uid", body.UID) // 设置该连接的会话值
    c.OK()
  })

  server.Handle("userinfo", func(c *tcpsrv.Context) {
    uid := c.Get("uid").(int64) // 获取会话值
    c.OK(findUserByUID(uid)) // OK 可设置响应数据,如果不设置
  })
}
客户端

客户端是该协议的实现,在符合上述协议的服务器都可使用

package main

import (
  "github.com/go-eyas/toolkit/tcp"
  "github.com/go-eyas/toolkit/tcp/tcpsrv"
  "fmt"
)

func main()  {
    client, err := tcpsrv.NewClientSrv(&tcp.Config{
      Addr:    ":6601",

      // 自定义tcp数据包协议,实现下方两个方法即可
      // 将业务数据封装成tcp数据包
      // Packer: func(data []byte) ([]byte,  error) {}, 
      // 将 tcp 连接收到的数据包解析成业务数据,返回的业务数据必须符合上方定义的 json 数据
      // Parser: func(conn *tcp.Conn, pack []byte) ( [][]byte,  error) {}, 
    })
    if err != nil {
      panic(err)
    }
  
    // 每当服务器发送了数据过来,都会以 cmd 作为时间名触发事件
    client.On("register", func(response *tcpsrv.TCPResponse) {
      fmt.Println("on receive register msg:", response)
    })
  
    client.On("userinfo", func(response *tcpsrv.TCPResponse) {
      fmt.Println("on receive userinfo msg:", response)
    })
  
    // send 发送后,会等待服务器的响应,res 为服务器的响应数据
    res, err := client.Send("register", map[string]interface{}{
      "uid": 1234,
    })
    if err != nil {
      panic(err)
    }
    fmt.Println("send register response: ", res)
  
    res, err = client.Send("userinfo")
    if err != nil {
      panic(err)
    }
    // 响可直接解析绑定 data 数据
    res.BindJSON(&struct {
     UID int64
    }{})
    fmt.Println("send userinfo response: ", res)
}

API

API 文档

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ClientSrv

type ClientSrv struct {
	Engine  *tcp.Client
	Emitter *emit.Emitter
	// contains filtered or unexported fields
}

func NewClientSrv

func NewClientSrv(conf *tcp.Config) (*ClientSrv, error)

NewClientSrv 实例化客户端服务

func (*ClientSrv) On

func (cs *ClientSrv) On(cmd string, h func(*TCPResponse))

On 监听服务器响应数据,每当服务器有数据发送过来,都会以 cmd 为事件名触发监听函数

func (*ClientSrv) OnMessage added in v1.3.4

func (cs *ClientSrv) OnMessage(h func(*TCPResponse))

func (*ClientSrv) Pub

func (cs *ClientSrv) Pub(cmd string, data interface{}) error

Pub 给服务器发送消息

func (*ClientSrv) Send

func (cs *ClientSrv) Send(cmd string, datas ...interface{}) (*TCPResponse, error)

Send 给服务器发送消息,并等待服务器的响应数据,10秒超时

type Context

type Context struct {
	Values map[string]interface{} // 该会话注册的值

	CMD        string          // 命令名称
	Seqno      string          // 请求唯一标识符
	RawData    json.RawMessage // 请求原始数据 data
	SessionID  uint64          // 会话ID
	Socket     *tcp.Conn       // 长连接对象
	RawMessage *tcp.Message    // 原始消息对象
	Engine     *tcp.Server     // 引擎
	Server     *ServerSrv      // 服务器对象
	Payload    []byte          // 请求原始消息报文
	Request    *TCPRequest     // 已解析的请求数据
	Response   *TCPResponse    // 响应数据
	// contains filtered or unexported fields
}

Context 请求上下文

func (*Context) Abort

func (c *Context) Abort()

Abort 停止后面的处理函数和中间件执行

func (*Context) Bind

func (c *Context) Bind(v interface{}) error

Bind 解析并 JSON 绑定 data 数据到结构体,并验证数据正确性

func (*Context) Get

func (c *Context) Get(key string) interface{}

Get 获取会话的值

func (*Context) Next

func (c *Context) Next()

func (*Context) OK

func (c *Context) OK(args ...interface{}) error

OK 响应成功数据

func (*Context) Push

func (c *Context) Push(data *TCPResponse) error

Push 服务器主动推送消息至该连接的客户端

func (*Context) Set

func (c *Context) Set(key string, v interface{})

Set 设置会话的上下文的值,注意设置的值在整个会话生效,不仅仅在本次上下文请求而已

type ServerSrv

type ServerSrv struct {
	Engine *tcp.Server
	Config *tcp.Config

	Session map[uint64]map[string]interface{} // map[sid]SessionData
	// contains filtered or unexported fields
}

func NewServerSrv

func NewServerSrv(conf *tcp.Config) (*ServerSrv, error)

func (*ServerSrv) Destroy

func (srv *ServerSrv) Destroy(sid uint64)

func (*ServerSrv) Handle

func (srv *ServerSrv) Handle(cmd string, handlers ...TCPHandler)

Handle 注册 CMD 路由监听器

func (*ServerSrv) Push

func (srv *ServerSrv) Push(sid uint64, data *TCPResponse) error

Push 服务器推送消息到客户端

func (*ServerSrv) Use

func (srv *ServerSrv) Use(h ...TCPHandler)

处理器中间件

type TCPClientRequest

type TCPClientRequest struct {
	CMD   string      `json:"cmd"`
	Seqno string      `json:"seqno"`
	Data  interface{} `json:"data"`
}

WSRequest 请求数据

type TCPHandler

type TCPHandler func(*Context)

type TCPRequest

type TCPRequest struct {
	CMD   string          `json:"cmd"`
	Seqno string          `json:"seqno"`
	Data  json.RawMessage `json:"data"`
}

WSRequest 请求数据

func (*TCPRequest) BindJSON

func (r *TCPRequest) BindJSON(v interface{}) error

func (*TCPRequest) SetJSON

func (r *TCPRequest) SetJSON(v interface{}) (err error)

type TCPResponse

type TCPResponse struct {
	CMD    string          `json:"cmd"`
	Seqno  string          `json:"seqno"`
	Status int             `json:"status"`
	Msg    string          `json:"msg"`
	Data   json.RawMessage `json:"data"`
}

WSResponse 响应数据

func (*TCPResponse) BindJSON

func (r *TCPResponse) BindJSON(v interface{}) error

func (*TCPResponse) SetJSON

func (r *TCPResponse) SetJSON(v interface{}) (err error)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL