共计 1568 个字符,预计需要花费 4 分钟才能阅读完成。
简介
目前大部分游戏、移动互联网、H5 客户端主要由 JavaScript、Lua、C#、C++ 等语言进行逻辑开发, 其主要通讯方案便是基于 HTTP 协议的接口请求与 Websocket 的推送方案.
起因
skynet
内部实现了一套同步非阻塞 socket
库, 并且提供了 TCP 通讯方案进行数据流分割. 所谓的 TCP 数据流 分割
. 就是根据一定方式读取数据的一种流程.
最为常见的数据分割方案应该是: 2 字节头部 + 数据载荷. 另一种通用方案是将头部扩展为 4 字节, 这样在头部信息中可以包含协议版本或者消息类型还可以进行平滑的进行协议升级扩展.
这些方案一般用于定制 C / S 网络协议. 绝大多数场景中并没有必须使用到这个场景, 且维护一套这样的协议也是需要占用开发周期的. 本人也使用过国内的开发者基于 skynet 编写的 websockket 开发库. 就使用上来说效果不是很理想, 且期间遇到的一系列问题也需要自己实际定制化后才能解决.
刚好近期由于正在为开发的 Lua Web 框架编写 Websocket 使用教程, 那么干脆趁这个机会为 skynet 移植一套专用的 websocket 库.
编写完成后, 我将它随意的命名为: skynet-lua-websocket
.
开始移植工作
1. 握手流程
skynet
要使用 Websocket 协议进行通讯需要实现 HTTP/1.1 版本中 101 响应方法. skyent.httpd
库可以完成 HTTP 协议的解析工作, 但是我们并没有使用到它.
究其原因是因为 websocket 实现交互并不复杂且所以无需依赖其它应用层协议库的实现. HTTP 本身就是一个基于文本的交互协议, 我们可以通过文本分割方案来完成它.
当连接到来时我们需要定义一个方法来处理握手协议交互(do_handshak). 在握手期间我们需要等待客户端发送有效的 HTTP 请求数据(协议、方法、版本、头部等等).
在握手期间我们不能忘记给它加上一个超时限制(set_timeout), 这个限制需要然客户端在指定时间范围内完成握手. 否则, 只能断开连接来节省服务器资源开销.
当 HTTP 请求数据接收完毕后, 我们需要对头部信息进行简单的验证. 这个验证过程并不会很复杂, 因为我们只需要知道头部信息是否完整有效即可.
在验证完成与通过的时候, 我们需要返回一个协议升级成功的 101 回应来通知客户端, 可以使用 websocket 规定的协议进行通讯并且开始监听链接是否有数据即可.
2. 消息交互
Websocket
协议规范中定义了一些常用的消息(控制帧). 目前为止, 我们也仅需要使用到这些消息: text
、binary
、ping
、pong
、close
.
text/binary
可以分为一种客户端请求消息, 它定义了客户端发送到服务端的数据是什么类型. 这通常在项目开发初期已经约定好传输协议, 所以无需过多考虑.
ping/pong
通常是成对出现的; 它一般用作心跳检查 (虽然没有人这样做) 与交互测试工作.
close
一般主动推送关闭消息, 一般情况下接收到这样的消息的处理方式为关闭连接.
3. 事件处理
事件处理方式就仿照 JavaScript 设计定义了 4 种回调函数类型(on_open
、on_message
、on_error
、on_close
), 这样能简化代码编写难度.
在每个客户端连接到来的时候为用户初始化 ctor
方法并为其注入 ws
对象用于与客户端进行通讯 (send
、close
). 当客户端连接建立完成后会在应用层触发on_open
方法, 让开发者此时做一些相关的初始化的操作.
期间与客户端连接保持的期间内定义了 on_message
方法用于接收客户端的数据, 对需要回应的数据可以使用 self.ws:send
方法进行消息回应.
最后, 我们可以在连接完成 (断开) 的时候触发 on_close
方法, 集中式资源回收更加简单.
使用方法
可以通过这里的描述学习如何使用它.
下载
项目地址在这里.