zoukankan      html  css  js  c++  java
  • pomelo 协议



    分析hybridconnector。使用chatofpomelo-websocket(pomelo至0.7.0)
    参考:https://github.com/NetEase/pomelo/wiki/Pomelo-协议
    http://cnodejs.org/topic/51395fd0df9e9fcc5882576c


    client握手:


    pomelo在init时候。创建WebSocket连接。并定义onopen onmessage回调。
    连接建立后,onopen被回调。client首先发送握手包var obj = Package.encode(Package.TYPE_HANDSHAKE, Protocol.strencode(JSON.stringify(handshakeBuffer)));
    參数为,假设version在client有缓存。将使用缓存{
      'sys': {
        'version': '1.1.1',
        'type': 'js-websocket'
      }, 
      'user': {
        // any customized request data
      }
    }
    这种方法中。package格式为type。length,body,传入的參数为type和body。


    服务端发回message,在onmessage中处理server到client的握手响应,服务端发回的參数
    {
      'code': 200,          // result code
      'sys': {
        'heartbeat': 3,     // heartbeat interval in second
        'dict': {},         // route dictionary
        'protos': {}        // protobuf definition data
      }, 
      'user': {
        // any customized response data
      }
    }
    并分发到handshake处理,首先缓存dict和protos。然后发回var obj = Package.encode(Package.TYPE_HANDSHAKE_ACK);握手ack,至此握手完成




    client打包:
    Package分为header和body两部分。Header描写叙述package包的类型和包的长度,body则是须要传输的数据内容。详细格式參考https://github.com/NetEase/pomelo/wiki/Pomelo-通讯协议
    package的body部分发送的是Message,消息头分为三部分。flag。message id,route。详细格式參考https://github.com/NetEase/pomelo/wiki/Pomelo-通讯协议


    Package.encode,打包函数比較简单,仅仅是转换大小端
    Message.encode。Message的打包函数。第一步是计算包长度。message id可变,要计算,是否有路由。要计算,加上发送的内容,就是总长度,然后创建buffer填充内容。
    填充内容时候。假设有路由压缩,则在填充路由的时候,填充替换过的路由。


    pomelo.encode 用户数据打包函数。这个打包的结果是Message.encode中的msg。这个函数用了处理路由压缩和protobuf压缩。
    假设clientProtos中配置了路由,将用 protobuf.encode(route, msg);打包内容。假设dict定义了路由,将替换路由


    程序运行的顺序刚好与以上介绍反过来,先内层后外层


    client解包:
    Package.decode,解包出类型和长度
    Message.decode。解包id,路由,和body。注意id和路由可能不存在
    pomelo.decode。假设有id。则说明是request,直接从routeMap中替换路由。然后deCompose。路由有compressRoute。则替换路由。serverProtos中要求打包路由,则用protobuf.decode解包内容


    解包刚好是正常的运行顺序。先外层后内层






    服务端:


    使用的hybridconnector中的websocket链接


    hybridconnector和hybridsocket是pomelo封装的server和socket,switch是转发。wsprocessor是websocket处理的文件,commands目录是握手,心跳处理的逻辑


    hybridconnector用 this.tcpServer = net.createServer();接受连接。

    switch分发tcp和websocket。到processor处理


    对于websocket的连接建立过程:
    1:switch中的tcpServer转发connection到newSocket处理,newSocket将connection转发给wsprocessor处理
    2:Processor.prototype.add中,httpServer分发connection消息(由于pomelo自己用net接受的连接。所以要自己用httpserver解析http协议),
    http.js中用connectionListener函数处理connection消息。仅仅是为socket加入了一下处理函数(ondata下一步会用到)。
    3:由于socket.ondata存在,所以直接调用,在http.js中看到ondata相应websocket来说,是为了分发upgrade消息
    4:在httpserver的外层还有WebSocketServer。WebSocketServer在创建的时候,会注冊httpserver的upgrade消息,用于建立websocket连接,同一时候分发connection消息
    5:processor在创建的时候,注冊了websocketserver的connection消息。并再次分发
    6:switch转发了processor的connection消息
    7:hybridconnector注冊了switch的connection消息,用socket封装成hybridsocket,并为hybridsocket注冊handshake heartbeat disconnect closing消息,同一时候分发connection消息
    8:组件connector在初始化时,注冊了hybridconnector的connection消息,用bindEvents。为hybridsocket注冊了disconnect  error message消息,至此连接建立


    对于websocket的握手过程:
    1:消息的起源处是,socket分发message消息,在hybridsocket中。收到消息。用Package.decode(msg)解包。解包函数与client一致,握手请求分发到handleHandshake,分发传入的socket为hybridsocket类型
    2:handleHandshake将上一步解析出的msg。将body通过JSON.parse(protocol.strdecode(msg.body))转成json。用handshake消息分发出去
    3:在hybridconnector中,參考【websocket的连接建立过程】7。连接时候已经注冊了handshake处理方法,将转发给handshake.handle
    4:在commands的handshake中。參数heartbeat  dict sys被收集,通过服务端的握手包返回给client


    5:但服务端收到握手ack包时,服务端回复client心跳包,(socket.emit('heartbeat');),至此握手完毕


    服务端心跳逻辑:
    1:握手完毕后,hybridsocket分发heartbeat消息,在commands中的heartbeat处理。在heartbeats字典中。存储计时器,将在心跳时间后,发送心跳包。并注冊超时函数


    2:当收到client的心跳包后,在hybridsocket处handleHeartbeat中处理,分发heartbeat消息。

    在commands中的heartbeat中,要先清理超时回调,然后同1




    服务端响应request:
    1:消息的起源处是。socket分发message消息,在hybridsocket中,收到message消息。用Package.decode(msg)解包,解包函数与client一致,通过hybridsocket分发解析后的msg
    2:參考【websocket的连接建立过程】8。在connector处理了解析后的msg,首先调用 self.connector.decode(msg);hybridconnector中的decode与client的解包一致,
    先调用Message.decode(msg.body);然后替换路由,和用protobuf解压缩
    3:然后handleMessage,将解析后的请求。分发到相应的server处理,回调的结果通过self.send(msg.id, msg.route, resp, [session.id], {isResponse: true}, function() {});返回给client
    send中会将发送的内容通过emsg = this.connector.encode(reqId, route, msg);打包成message,代码在hybridconnector中。与client逻辑同样
    4:connector的send方法,通过组件__pushScheduler__发送,并在下一帧调用回调函数(reqest的回调为空函数)
    5:组件__pushScheduler__发送,不论是广播还是推送,都是通过sessionService.sendMessage发送。然后调用session的send方法
    6:sessionservice逻辑中,session是在【websocket的连接建立过程】8中的bindevents中生成的,成员变量__socket__这是hybridsocket。所以,session的send方法hybridsocket的send实现
    7:hybridsocket的send在this.sendRaw(Package.encode(Package.TYPE_DATA, msg)); 此时在服务器上完成request响应


    服务端push不再多说细节

  • 相关阅读:
    HDU4628+状态压缩DP
    Javascript 去掉字符串前后空格的五种方法
    Javascript 数组之判断取值和数组取值
    ASP.NET MVC 出现错误 “The view 'XXX' or its master was not found or no view engine support”
    ASP.NET MVC 页面调整并传递参数
    ASP.NET MV3 部署网站 报"Could not load file or assembly ' System.Web.Helpers “ 错的解决方法
    ASP.NET MVC 控制器向View传值的三种方法
    CSharp 如何通过拼接XML调用存储过程来查询数据
    SQLServer : EXEC和sp_executesql的区别
    关于SQLServer2005的学习笔记—异常捕获及处理
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/4582583.html
Copyright © 2011-2022 走看看