为skynet移植一个lua-websocke库
简介
目前大部分游戏、移动互联网、H5客户端主要由JavaScript
、Lua
、C#
、C++
等语言进行逻辑开发, 其主要通讯方案便是基于HTTP
协议的接口请求与Websocket
的推送方案.
起因
skynet
内部实现了一套同步非阻塞socket
库, 并且提供了TCP
通讯方案进行数据流分割. 所谓的TCP数据流分割
. 就是根据一定方式读取数据的一种流程.
最为常见的数据分割方案应该是: 2字节头部 + 数据载荷. 另一种通用方案是将头部扩展为4字节, 这样在头部信息中可以包含协议版本或者消息类型还可以进行平滑的进行协议升级扩展.
这些方案一般用于定制C/S
网络协议. 绝大多数场景中并没有必须使用到这个场景, 且维护一套这样的协议也是需要占用开发周期的.本人也使用过国内的开发者基于skynet编写的websockket开发库. 就使用上来说效果不是很理想, 且期间遇到的一系列问题也需要自己实际定制化后才能解决.
刚好近期正在为自己开发的Lua Web框架编写教程, 那么干脆趁这个机会将它实现的Websocket
协议库也移植到skynet
上去.
编写完成后, 我将它随意的命名为: 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
). 当客户端连接建立完成后会在应用层触发open
方法, 让开发者此时做一些相关的初始化的操作.
期间与客户端连接保持的期间内定义了on_message
方法用于接收客户端的数据, 对需要回应的数据可以使用self.ws:send
方法进行消息回应.
最后, 我们可以在连接完成(断开)的时候触发on_close
方法, 集中式资源回收更加简单.
使用方法
可以通过这里的描述学习如何使用它.
下载
项目地址在这里.