Pomelo 0.5.5 源码分析(2)-通信
客户端与服务器的通信
客户端的通信在 pomelo-client 里封装了。
服务器与客户端的通信在 connector 里。底层提供 WebSocket、TCP 和 socket.io 三种方式的通信。
connector 组件(components/connector.js)
组件构造函数里会 this.connector
从 opts 里取 connector,或者默认为 connectors/sioconnector.js。(connector 的实现 sioconnector 和 hybridconnector)
组件的 start
里会将 this.server\this.session\this.connection
分别映射到 app
的对应的组件上。
组件的 afterStart
里 this.connector.start
,并监听 this.connector
的 connection 事件。
connection 事件处理为: 将 connection 关联一个 session,监听 socket 的 message 事件,接受到 message 时 decode message,再将 message 交给 server 组件的 handle
,处理完回调里再将返回信息在 connector 组件的 send
里处理。
另外监听 session 的 bind 事件,处理函数为,调用 connection.addLoginedUser
。
组件里的 send,encode reponse 的 message,然后交给 schedule 组件的 schedule。
hybridconnector 的实现
connectors/hybridconnector.js 以及connectors/hybird。hyrbird 实现了原生 Socket 和 WebSocket 两种。
hybridconnector.start
里会 this.tcpServer=net.createServer
,然后把以这个 tcpServer
为参数创建一个 switcher。之后在 switcher 的 connection 事件里将 tcpsocket
装进 hybridsocket
。
hybrid/switcher.js
switcher 构造函数接受一个 server 参数,并创建 this.wsprocessor
和 this.tcpprocessor
。
switcher 监听参数 server 的 connection 事件,事件处理函数里监听原生 socket 的 data 事件,判断 data 是否有 HTTP 头,如果有,则调用 wsprocessor.add
,这个 add
会向外 emit ‘connection’(事件参数为原生 socket),并向 socket emit ‘data’ 事件;否则非HTTP,则调用 tcpprocessor.add
,这个 add 会以刚才的原生 socket 为参数创建一个 tcpsocket,同时向 tcpprocessor emit ‘connection’(事件参数为原生 tcpsocket)、向这个原生 socket emit ‘data’ 事件。
switcher也监听了 this.wsprocessor
和 this.tcpprocessor
的 connection 事件,处理为向 switcher 自己 emit ‘connection’。总结,switcher 的职责,将 socket 的字节流 data 拼成包,以 message 事件向外 emit 一个个的完成包 msg。
刚才提到的 tcpsocket.js 这里处理原生 socket 的操作。监听了原生 socket 的 ‘data’、’end’、’error’、’close’ 事件。例如在 ‘data’ 处理时,当读入的流长度够一个包的 body 后就向 tcpsocket emit ‘message’。
hybridsocket.js
将 Socket 和 WebSocket 封装为统一接口。构造函数里接受一个 id 和 socket 参数。
hybridsocket
监听 tcpsocket
的 ‘message’ 事件,将 msg decode,之后处理。例如 Package.TYPE_DATA
类型的 msg,就将这个 msg 再向 hybridsocket
自己 emit 一个 ‘message’ 事件,其他可能是 ‘handshake’ 或 ‘heartbeat’ 事件。
server 组件
官方描述如下“模块使服务器具备处理客户端请求的能力。该模块主要实现了 filter 服务,根据当前服务器类型,加载对应 handler 目录下的代码,并决定一个请求应该是在当前服务器处理还是应该路由给其他服务器处理。”,下面看看代码流程。
组件的start里初始化filter和handler。
服务器之间的通信
框架调用
session
session 组件(components/session.js)
session 组件直接用的 common/service/sessionService
。
sessionService
Session(object)
Session 里维护的 socket 和 user 信息的之间的对应关系。每个 socket 有个对应的 Session,验证用户身份后就将他们绑定。
Session 构造函数接受参数 socket id\frontendId\socket\service
。
Session通过 bind\unbind
函数将 uid 绑到 this.uid 里,并 emit ‘bind’’unbind’ 事件。
Session的 set\get
函数来给 Session 设取值,由 this.settings
维护。
Session的 send\sendBatch
都是直接通过构造时传入的那个 socket 来操作。
MockLocalSession(object)
SessionService(object)
负责对 Session 的管理。构造函数里将 this.sessions
和 this.uidMap
初始为空表。
SessionService 的 create
负责 new Session,并放到 this.sessions
里。
bind\unbind
函数负责将传入的 siduid 对应绑定到 this.sessions\this.uidMap
里。uidMap
里每个元素是个数组,所以每个 uid 可以对应多个 session?(这个以后再具体了解下)
sendMessage\sendMessageByUid
根据 siduid 往对应的 session 或 sessions 发消息。
其他函数不一一列举了。
session的使用
看了下 chatofpomelo 里,是在 connector/handler/entryHandler.js 里的 enter
函数,直接用了 session.bind
。简单用法就是在自己项目的验证 uid 后自己绑定。
pomelo-rpc
rpc-client
rpc-server
lib/rpc-server/server 将远程调用处理下,加到 opts.services
里,然后通过 gateway 来 listen 端口和处理 message。