skynet源码分析:Socket

skynet 的 C API 采用异步读写,你可以使用 C 调用,监听一个端口,或发起一个 TCP 连接。但具体的操作结果要等待 skynet 的事件回调。skynet 会把结果以 PTYPE_SOCKET 类型的消息发送给发起请求的服务。(参考skynet_socket.h)

在处理实际业务中,这样的 API 很难使用,所以又提供了一组阻塞模式的 lua API 用于 TCP socket 的读写。它是对 C API 的封装。

所谓阻塞模式,实际上是利用了 lua 的 coroutine 机制。当你调用 socket api 时,服务有可能被挂起(时间片被让给其他业务处理),待结果通过 socket 消息返回,coroutine 将延续执行。

SocketChannel


请求回应模式是和外部服务交互时所用到的最常用模式之一。通常的协议设计方式有两种。

  1. 每个请求包对应一个回应包,由 TCP 协议保证时序。redis 的协议就是一个典型。每个 redis 请求都必须有一个回应,但不必收到回应才可以发送下一个请求。

  2. 发起每个请求时带一个唯一 session 标识,在发送回应时,带上这个标识。这样设计可以不要求每个请求都一定要有回应,且不必遵循先提出的请求先回应的时序。MongoDB 的通讯协议就是这样设计的。

对于第一种模式,用 skynet 的 Socket API 很容易实现,但如果在一个 coroutine 中读写一个 socket 的话,由于读的过程是阻塞的,这会导致吞吐量下降(前一个回应没有收到时,无法发送下一个请求)。

对于第二种模式,需要用 skynet.fork 开启一个新线程来收取回应包,并自行和请求对应起来,实现比较繁琐。

所以、skynet 提供了一个更高层的封装:socket channel 。

关于 socket channel 的具体用法除了阅读 lualib/socketchannel.lua (同时这也是理解 socket 模块的好材料)的实现外,也可以阅读 lualib/redis.lua 和 lualib/mongo.lua 这两个为 skynet 编写的数据库 driver 。

mysql

在这个 fork https://github.com/chfg007/skynet 里,实现了 mysql 的 driver (改自 OpenResty)。

主要文件为 lualib/mysql.lua 和 3rd/lua-mysqlaux

local status, err = pcall(mysqldb.query,mysqldb,sqlstr) 记得捕获错误,有可能查询的时候链接已经断开。

https://github.com/cloudwu/skynet/wiki/SocketChannel

猜你喜欢

转载自www.cnblogs.com/losophy/p/9267937.html