We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
根据之前的项目经验梳理了一下对于服务器端长连接(websocket, tcp)的开发模式,并且总结出了一套解决方案
先看看HTTP的开发模式有哪些爽点
还有其他爽点,可是这些在 WebSocket, TCP 就不适用了。
在长连接的开发中,相比于http的开发,会遇到这些问题:
Command Service
参考 HTTP 的开发模式。首先要定义一个请求响应的协议规范
// Request 请求协议 type Request struct { Cmd string // 消息命令,用于路由映射 Seqno string // 消息编号,在短时间内不能重复 RawData []byte // 消息原始数据 } // Response 响应协议 type Response struct { Cmd string // 消息命令 Seqno string // 消息编号,请求的 Seqno 原样赋值 Code int // 响应状态码 Msg string // 响应消息 Data interface{} // 响应的数据 }
Request 是请求数据,Response 是响应数据、服务器推送数据,整个框架将会围绕该协议做进一步的封装。
Request
Response
一旦有固定的协议了,那么就可以很方便的做很多事了,比如 HTTP 那么爽,围绕 HTTP 框架的功能,让我们把 HTTP 框架有的东西也给弄过来。
模拟HTTP的开发模式,绑定路由,路由分组,中间件请求处理,参数解析,验证,格式化响应等等。
此外,还有长连接特有的功能,主动推送,获取其他连接状态
srv := cs.New() srv.Use(cs.Recover()) // 使用中间件 srv.Handle("register", func(c *cs.Context) { // 绑定路由 var body struct{ UID int64 `json:"" v:"required#uid必填"` Name string `json:"" v:"required#name必填"` } if err := c.Parse(&body); err != nil { panic(err) // panic 给 recover 中间件处理 } c.Set("uid", body.UID) // 给当前连接设置状态 c.OK(map[string]int64{ // 响应数据 "timestamp": time.Now().Unix(), }) c.Push(&cs.Response{ // 主动给当前连接推送消息 Cmd: "welcome", Data: "welcome to my server" }) c.Broadcast(&cs.Response{ // 广播,给所有连接推消息 Cmd: "user_online", Data: body, }) for _, sid := range c.GetAllSID() { if c.GetState(sid, "uid") != nil { // 获取其他连接的状态,然后给其他连接推消息 c.PushSID(sid, &cs.Response{ Cmd: "friend_online", Data: map[string]interface{}{ "name": body.Name, } }) } } })
瞧,只要把基础协议一固定,什么都好做了。而且功能比 HTTP 更强,更方便了。
如果把协议定的很死,那么就少了很多的灵活性,局限就很大了。所以上面的协议,可以理解为业务协议,实际上数据包的协议完全由适配器自己去决定,然后把数据包转成上方的协议就可以完美使用刚刚封装的框架。
比如 tcp 的一个数据包协议为 [数据长度 4byte] + [命令2byte] + [版本号1byte] + [数据不固定长度], 就可以根据该协议提取出 命令,、数据,转化为上方的协议,&cs.Request{Cmd: parsedCmd, Data: parseDataBytesArray}
[数据长度 4byte] + [命令2byte] + [版本号1byte] + [数据不固定长度]
&cs.Request{Cmd: parsedCmd, Data: parseDataBytesArray}
该框架做到后面,我发现要将多个适配器共享一套代码变得特别容易,比如 TCP 和 Websocket 共用同一套业务逻辑,只需要实现好适配器就可以了,真是意外惊喜
wsAdapter := xwebsocket.New() tcpAdapter := xtxp.New("127.0.0.1:5566") srv := cs.New(httpAdapter, tcpAdapter) srv.Handle(cs.CmdConnected, func (c *cs.Context) {})
再到后面,发现要实现 HTTP 主动推送也是特别简单的,基于 SSE 的主动推送,加上 HTTP 的请求响应模式,在加上 cookie 对于连接的状态维护
The text was updated successfully, but these errors were encountered:
No branches or pull requests
简化 WebSocket, TCP 等长连接的开发
简介
根据之前的项目经验梳理了一下对于服务器端长连接(websocket, tcp)的开发模式,并且总结出了一套解决方案
HTTP 开发模式
先看看HTTP的开发模式有哪些爽点
还有其他爽点,可是这些在 WebSocket, TCP 就不适用了。
长连接的痛点
在长连接的开发中,相比于http的开发,会遇到这些问题:
解决方案
Command Service
协议
参考 HTTP 的开发模式。首先要定义一个请求响应的协议规范
Request
是请求数据,Response
是响应数据、服务器推送数据,整个框架将会围绕该协议做进一步的封装。路由映射,处理上下文
一旦有固定的协议了,那么就可以很方便的做很多事了,比如 HTTP 那么爽,围绕 HTTP 框架的功能,让我们把 HTTP 框架有的东西也给弄过来。
模拟HTTP的开发模式,绑定路由,路由分组,中间件请求处理,参数解析,验证,格式化响应等等。
此外,还有长连接特有的功能,主动推送,获取其他连接状态
瞧,只要把基础协议一固定,什么都好做了。而且功能比 HTTP 更强,更方便了。
适配器
如果把协议定的很死,那么就少了很多的灵活性,局限就很大了。所以上面的协议,可以理解为业务协议,实际上数据包的协议完全由适配器自己去决定,然后把数据包转成上方的协议就可以完美使用刚刚封装的框架。
比如 tcp 的一个数据包协议为
[数据长度 4byte] + [命令2byte] + [版本号1byte] + [数据不固定长度]
, 就可以根据该协议提取出 命令,、数据,转化为上方的协议,&cs.Request{Cmd: parsedCmd, Data: parseDataBytesArray}
多适配器共享
该框架做到后面,我发现要将多个适配器共享一套代码变得特别容易,比如 TCP 和 Websocket 共用同一套业务逻辑,只需要实现好适配器就可以了,真是意外惊喜
HTTP 主动推送
再到后面,发现要实现 HTTP 主动推送也是特别简单的,基于 SSE 的主动推送,加上 HTTP 的请求响应模式,在加上 cookie 对于连接的状态维护
The text was updated successfully, but these errors were encountered: