pomeloコード分析7————pomeloのrpcは分析を実現します.


どこに書きたいですか?前の穴が邪魔にならないなら、記入しません.へへ~
RPC:remote procedule call;なんですか?言いません.
以下は直接pomeloの実現を見ます.
対応moduleはpomelo-rpcで、これは直接npm installでインストールできます.
例えば、npm install-d pomelo-rpcは、現在のディレクトリのnode_にダウンロードされます.modulesディレクトリの中にあります.
インストール完了後のディレクトリは以下の通りです.
AUTHORS  index.js  lib  LICENSE  Makefile  node_modules  package.json  README-Chinese.md  README.md  sample  test
実際にpomelo-rpcは他の多くのmoduleに依存しています.具体的にこれらのmoduleは何のために使いますか?これは言いません.自分で見てください
直接に:
まずsampleディレクトリは以下の通りです.
sample/
├── client.js
├── remote
│   └── test
│       └── service.js
└── server.js
直接node server.jsは、clientのrpc呼び出しを待つserverを起動することができます.
私たちは他の端末にいます.node client.jsで結果が見えます.
libの下に何がありますか?
lib/
├── rpc-client
│   ├── client.js
│   ├── mailboxes
│   │   ├── blackhole.js
│   │   ├── tcp-mailbox.js
│   │   └── ws-mailbox.js
│   ├── mailbox.js
│   ├── mailstation.js
│   └── router.js
├── rpc-server                    #rpc  server   
│   ├── acceptor.js               #  rpc Factory,      ,          ws-acceptor.js,   websocket   。
│   ├── acceptors                 #          
│   │   ├── tcp-acceptor.js          #tcp
│   │   └── ws-acceptor.js           #websocket
│   ├── dispatcher.js             #rpc     ,                       rpc    。
│   ├── gateway.js                #          server,     start,stop,     acceptor callback   ———— dispatcher
│   └── server.js                 #1、    ,             gateway。2:                  。
└── util
    ├── proxy.js
    ├── tracer.js
    └── utils.js
OK、ファイルからserverの論理タイミングは以下の通りです.
server.js:落1、モジュールをロードし、モジュールをパラメータとして初期化するgateway.2)ツリー構造を構築し、これらの初期化されたモジュールを登録する
gateway.js:钻初期化acceptorのcalback関数————dispatcher
         acceptor.js:菗accepterのfactory、ここではwsタイプだけを生産しているacceptorが死んだと書いてあります.
          ws-acceptor.js Swebsocket方式の受信機は具体的に実現される.
登録されたmoduleは、dispatcher.js:Cientが呼び出したツリー構造に基づいて簡単に検索され、moduleを呼び出します.
コードをかき集める:
第一部分:登録して、calbackのツリー構造を生成する.
sample/server.js
  1 var Server = require('..').server;
  2  
  3 debugger;
  4 // remote service path info list
  5 var paths = [
  6   {namespace: 'user', path: __dirname + '/remote/test'}  #          module, sample    。
  7 ];
  8                                                                                                                                                            
  9 var port = 3333;
 10  
 11 var server = Server.create({paths: paths, port: port});
 12 server.start();
 13 console.log('rpc server started.');
pomeloの中のrpcはパッケージを使って綺麗です.
このうち、11ギルドはlib/rpc-server/server.jsファイルのcreate関数を呼び出します.以下の通りです.
module.exports.create = function(opts) {
  if(!opts || !opts.port || opts.port < 0 || !opts.paths) {
    throw new Error('opts.port or opts.paths invalid.');
  }

  var services = loadRemoteServices(opts.paths, opts.context);
  opts.services = services;
  var gateway = Gateway.create(opts);
  return gateway;
};
実は一つのserverはgatewayなのです!
このgatewayは、loadRemoteServicesによって生成された一連のservicesをパラメータとして受け入れます.
この関数をもう一度見ます.
  4 var loadRemoteServices = function(paths, context) {
  5   var res = {}, item, m;
  6   for(var i=0, l=paths.length; i<l; i++) {
  7     item = paths[i];
  8     m = Loader.load(item.path, context);
  9  
 10     if(m) {
 11       createNamespace(item.namespace, res);
 12       for(var s in m) {
 13         res[item.namespace][s] = m[s];
 14       }
 15     }
 16   }
 17  
 18   return res;
 19 };
 20  
 21 var createNamespace = function(namespace, proxies) {
 22   proxies[namespace] = proxies[namespace] || {};
 23 };
 24  
その中のload()前の文章はもう話しました.pomelo-loaderです.だからmは一つのmoduleです.
前に述べたように、すべてのmodule生成作業とexport導出作業は、ロード()関数で完了しました.
10行目の後ろのコードは組織resのためだけです.コードをよく見たり、debugerで印刷したりします.
>res
  Object
    user: Object
      service: Object
        echo: function (msg, cb) {  ...
pomeloは、初期化時に導入されたnamespace、jsモジュールのファイル名、moduleのexports名に基づいて構築され、
res[namespace][filename][exports.name]=m[exports.name]
ここはツリーの登録です.後のclientにコールされるのを待っています.
具体的なコールロジックは以下の通りです.
第二部分:起動、トリガロジック
上の第一部はすでにすべてのmoduleを登録しました.server.start()の時は、gateway.start()を呼び出して、さらにaccepter.listen()を呼び出します.
ここのacceptorはws-accptor.jsです.対応部分のコードは以下の通りです.
pro.listen = function(port) {
  //check status
  if(!!this.inited) {
    utils.invokeCallback(this.cb, new Error('already inited.'));
    return;
  }
  this.inited = true;

  var self = this;

  this.server = sio.listen(port);             # 1、   ,  socket.io listen     。

  this.server.set('log level', 0);

  this.server.server.on('error', function(err) {  #    ,   。。
    self.emit('error', err);
  });

  this.server.sockets.on('connection', function(socket) { #2、  client     ;
    self.sockets[socket.id] = socket;

    self.emit('connection', {id: socket.id, ip: socket.handshake.address.address});

    socket.on('message', function(pkg) {                 #3、        ,     “message”   ProcessMsgs()  。  
      try {
        if(pkg instanceof Array) {
          processMsgs(socket, self, pkg);
        } else {
          processMsg(socket, self, pkg);
        }
      } catch(e) {
        // socke.io would broken if uncaugth the exception
        console.error('rpc server process message error: ' + e);
      }
    });

    socket.on('disconnect', function(reason) {          #     ,   。。。
      delete self.sockets[socket.id]; 
      delete self.msgQueues[socket.id];
    });
  });

  this.on('connection', ipFilter.bind(this));          #   ,   。。。。

  if(this.bufferMsg) {
    this._interval = setInterval(function() {
      flush(self);
    }, this.interval);
  }
};
上記のコードのコメントを見ると、clientからメッセージが来たら、次の関数を呼び出します.
var processMsg = function(socket, acceptor, pkg) {
  var tracer = new Tracer(acceptor.rpcLogger, acceptor.rpcDebugLog, pkg.remote, pkg.source, pkg.msg, pkg.traceId, pkg.seqId);
  tracer.info('server', __filename, 'processMsg', 'ws-acceptor receive message and try to process message');
  acceptor.cb.call(null, tracer, pkg.msg, function() {        #####      ##########################
    var args = Array.prototype.slice.call(arguments, 0);
    for(var i=0, l=args.length; i<l; i++) {
      if(args[i] instanceof Error) {
        args[i] = cloneError(args[i]);
      }
    }
    。。。。。。。。。。。。。。。。。。。。。。
続いて上に述べました.一旦clientからメッセージがあったら、私達はprocessMsgを呼び出します.プロcessMsgはacceptorのコールバック関数を呼び出します.つまりdispatcher.route関数です.
これはgateway初期化の時にacceptorにかけられたものです.具体的なコードは以下の通りです.
  this.acceptor = this.acceptorFactory.create(opts, function(tracer, msg, cb) {
    dispatcher.route(tracer, msg, self.services, cb);
  });
このrouteはいったい何をしていますか?
module.exports.route = function(tracer, msg, services, cb) {
  tracer.info('server', __filename, 'route', 'route messsage to appropriate service object');
  var namespace = services[msg.namespace];

  var service = namespace[msg.service];


  var method = service[msg.method];

  var args = msg.args.slice(0);
  args.push(cb);
  method.apply(service, args);
};
 上のコードはエラーチェックを抜き、まっすぐに見えます.
はい、
methode=services[msg.namespace][msg.sevice][msg.method]だけです.
ここのmsg属性は以下の通りです.
namespace:「user」
service:「service」method:「echo」
見ましたよね.上の第一部を登録する時に作った木の形の構造です.
clientが呼び出した時に書いた不一致があると、上記のコードの中でエラー検出部分が淘汰されます.
OK、終了:
まとめ:
第一歩:Serverはツリー型の対応関係を構築する.
そして、clientから渡され、解析されたJSONに基づいてツリー構造に対応する関数を検索して呼び出します.
===========以下にクリエートを見て、