pomelo源代码分析(一)

千里之行始于足下,一直说想了解pomelo,对pomelo有兴趣,但一直迟迟没有去碰,尽管对pomelo进行源代码分析,在网络上肯定不止我一个,已经有非常优秀的前辈走在前面,如http://golanger.cn/,在阅读Pomelo代码的时候,已经连载到了11篇了,在我的源代码分析參考了该博客,当然,也会添?我对pomelo的理解,借此希望能提高一下自己对node.js的了解和学习一些优秀的设计。

  • 开发环境:win7
  • 调试环境:webstorm5.0
  • node.js版本号:v0.8.21
  • 源代码版本号package.json:
{
	"name": "chatofpomelo",
	"version": "0.0.1",
	"private": false,
	"dependencies": {
		"pomelo": "0.2.0",
		"log4js": ">= 0.4.1",
		"crc": ">=0.0.1"
	}
}

gameserver/app.js

var pomelo = require(‘pomelo‘);
var routeUtil = require(‘./app/util/routeUtil‘);
/**
 * Init app for client.
 */
var app = pomelo.createApp();     //创建Application
app.set(‘name‘, ‘chatofpomelo‘);  //设置Application名字

// app configure
app.configure(‘production|development‘, function() {
	// route configures
	app.route(‘chat‘, routeUtil.chat);

	// filter configures
	app.filter(pomelo.timeout());
});

// start app
app.start();

process.on(‘uncaughtException‘, function(err) {
	console.error(‘ Caught exception: ‘ + err.stack);
});

注意:在webstorm下调试,可能由于工作文件夹的设置原因会导致应用的运行路径问题,导致无法读取配置文件,所以须要依据实际情况改动例如以下

var opt = {‘base‘:‘D:\\src\\pomelo\\chatofpomelo\\game-server‘}
var app = pomelo.createApp(opt);
app.set(‘name‘, ‘chatofpomelo‘);

opt.base 是你的game-server的实际文件夹路径,详细能够依据自己须要来定制

app.js 是game-server的主要入口,主要负责创建application,读取配置文件,应用到application设置上,并利用app.start()来运行实际的master,monitor等服务器的start,对于聊天室程序来说,还要做简单的路由和过滤设置。

application, 应用的定义、component管理,上下文配置, 这些使pomelo framework的对外接口非常easy, 而且具有松耦合、可插拔架构。

全部server的启动都是从执行app.js開始。每个server的启动都首先创建一个全局唯一的application对象,该对象中挂载了所在server的全部信息,包含server物理信息、server逻辑信息、以及pomelo的组件信息等。同一时候,该对象还提供应用管理和配置等基本方法。 在app.js中调用app.start()方法后,application对象首先会通过loadDefaultComponents方法载入默认的组件。

pomelo/lib/pomelo.js

var application = require(‘./application‘);

Pomelo.createApp = function (opts) {
  var app = application;
  app.init(opts);
  self.app = app;
  return app;
};

pomelo/lib/application.js

/**
 * Application prototype.
 *
 * @module
 */
var Application = module.exports = {};

/**
 * Application states
 */
var STATE_INITED  = 1;  // app has inited
var STATE_START = 2;  // app start
var STATE_STARTED = 3;  // app has started
var STATE_STOPED  = 4;  // app has stoped

/**
 * Initialize the server.
 *
 *   - setup default configuration
 *
 * @api private
 */
Application.init = function(opts) {
  opts = opts || {};
  logger.info(‘app.init invoked‘);
  this.loaded = [];
  this.components = {};
  this.settings = {};   // set,和get功能的容器
  this.set(‘base‘, opts.base);  //设置服务器的工作文件夹
  this.defaultConfiguration();  //依据配置文件,载入master,monitor等服务器
  this.state = STATE_INITED;  //application工作状态
  logger.info(‘application inited: %j‘, this.get(‘serverId‘));
};

pomelo/lib/application.js

/**
 * Initialize application configuration.
 *
 * @api private
 */
Application.defaultConfiguration = function () {
  var args = utils.argsInfo(process.argv);
  this.setupEnv(args); //application环境设置
  this.loadServers();  //载入server配置信息
  this.loadConfig(‘master‘, this.getBase() + ‘/config/master.json‘); //载入materserver配置信息
  this.processArgs(args); //依据启动參数设定server配置
  this.configLogger();
};

utils.argsInfo(process.argv); 获取系统启动參数,我们最好还是看看究竟有哪些參数支持

启动game-server服务器:>pomelo start [development | production] [--daemon]

依据args參数设定application的工作环境是development或production

/**
 * Setup enviroment.
 * @api private
 */
Application.setupEnv = function(args) {
  this.set(‘env‘, args.env || process.env.NODE_ENV || ‘development‘, true);
};

载入服务器信息,而且保存在__serverMap___内存下

/**
 * Load server info from configure file.
 *
 * @api private
 */
Application.loadServers = function() {
  this.loadConfig(‘servers‘, this.getBase() + ‘/config/servers.json‘);
  var servers = this.get(‘servers‘);
  var serverMap = {}, slist, i, l, server;
  for(var serverType in servers) {
    slist = servers[serverType];
    for(i=0, l=slist.length; i<l; i++) {
      server = slist[i];
      server.serverType = serverType;
      serverMap[server.id] = server;
    }
  }

  this.set(‘__serverMap__‘, serverMap);
};

server.json

{
    "development":{
        "connector":[
             {"id":"connector-server-1", "host":"127.0.0.1", "port":4050, "wsPort":3050},
             {"id":"connector-server-2", "host":"127.0.0.1", "port":4051, "wsPort":3051},
             {"id":"connector-server-3", "host":"127.0.0.1", "port":4052, "wsPort":3052}
         ],
        "chat":[
             {"id":"chat-server-1", "host":"127.0.0.1", "port":6050},
             {"id":"chat-server-2", "host":"127.0.0.1", "port":6051},
             {"id":"chat-server-3", "host":"127.0.0.1", "port":6052}
        ],
        "gate":[
	     {"id": "gate-server-1", "host": "127.0.0.1", "wsPort": 3014}
	]
    },
    "production":{
       "connector":[
             {"id":"connector-server-1", "host":"127.0.0.1", "port":4050, "wsPort":3050},
             {"id":"connector-server-2", "host":"127.0.0.1", "port":4051, "wsPort":3051},
             {"id":"connector-server-3", "host":"127.0.0.1", "port":4052, "wsPort":3052}
         ],
        "chat":[
             {"id":"chat-server-1", "host":"127.0.0.1", "port":6050},
             {"id":"chat-server-2", "host":"127.0.0.1", "port":6051},
             {"id":"chat-server-3", "host":"127.0.0.1", "port":6052}
        ],
        "gate":[
	     {"id": "gate-server-1", "host": "127.0.0.1", "wsPort": 3014}
	]
  }
}

工具函数,读取json配置文件,在这里读取的是master.json文件

/**
 * Load Configure json file to settings.
 *
 * @param {String} key environment key
 * @param {String} val environment value
 * @return {Server|Mixed} for chaining, or the setting value
 *
 * @memberOf Application
 */
Application.loadConfig = function (key, val) {
  var env = this.get(‘env‘);
  val = require(val);
  if (val[env]) {
    val = val[env];
  }
  this.set(key, val);
};

master.json

{
    "development":{
        "id":"master-server-1",
        "host":"127.0.0.1",
        "port":3005,
        "queryPort":3015,
        "wsPort":2337
    },

    "production":{
        "id":"master-server-1",
        "host":"127.0.0.1",
        "port":3005,
        "queryPort":3015,
        "wsPort":2337
    }

}

依据进程读取配置好的參数,配置server。

Application.processArgs = function(args){
  var serverType = args.serverType || ‘master‘;
  var serverId = args.serverId || this.get(‘master‘).id;
  this.set(‘main‘, args.main, true);
  this.set(‘serverType‘, serverType, true);
  this.set(‘serverId‘, serverId, true);
  if(serverType !== ‘master‘) {
    this.set(‘curServer‘, this.getServerById(serverId), true);
  } else {
    this.set(‘curServer‘, this.get(‘master‘), true);
  }
};

项目的日志配置

Application.configLogger = function() {
  if(process.env.POMELO_LOGGER !== ‘off‘) {
    log.configure(this, this.getBase() + ‘/config/log4js.json‘);
  }
};

log4js.json

{
  "appenders": [
    {
      "type": "file",
      "filename": "./logs/node-log-${opts:serverId}.log",
      "fileSize": 1048576,
      "layout": {
        "type": "basic"
      },
      "backups": 5
    },
    {
      "type": "console"
    },
    {
      "type": "file",
      "filename": "./logs/con-log-${opts:serverId}.log",
      "pattern": "connector",
      "fileSize": 1048576,
      "layout": {
          "type": "basic"
        }
      ,"backups": 5,
      "category":"con-log"
    },
    {
      "type": "file",
      "filename": "./logs/rpc-log-${opts:serverId}.log",
      "fileSize": 1048576,
      "layout": {
          "type": "basic"
        }
      ,"backups": 5,
      "category":"rpc-log"
    },
    {
      "type": "file",
      "filename": "./logs/forward-log-${opts:serverId}.log",
      "fileSize": 1048576,
      "layout": {
          "type": "basic"
        }
      ,"backups": 5,
      "category":"forward-log"
    },
    {
      "type": "file",
      "filename": "./logs/crash.log",
      "fileSize": 1048576,
      "layout": {
          "type": "basic"
        }
      ,"backups": 5,
      "category":"crash-log"
    }
  ],

  "levels": {
  	"rpc-log" : "ERROR",
    "forward-log": "ERROR"
  }, 

  "replaceConsole": true
}
时间: 2024-10-25 20:14:12

pomelo源代码分析(一)的相关文章

Java中arraylist和linkedlist源代码分析与性能比較

Java中arraylist和linkedlist源代码分析与性能比較 1,简单介绍 在java开发中比較经常使用的数据结构是arraylist和linkedlist,本文主要从源代码角度分析arraylist和linkedlist的性能. 2,arraylist源代码分析 Arraylist底层的数据结构是一个对象数组.有一个size的成员变量标记数组中元素的个数,例如以下图: * The array buffer into which the elements of the ArrayLis

转:RTMPDump源代码分析

0: 主要函数调用分析 rtmpdump 是一个用来处理 RTMP 流媒体的开源工具包,支持 rtmp://, rtmpt://, rtmpe://, rtmpte://, and rtmps://.也提供 Android 版本. 最近研究了一下它内部函数调用的关系. 下面列出几个主要的函数的调用关系. RTMPDump用于下载RTMP流媒体的函数Download: 用于建立网络连接(NetConnect)的函数Connect: 用于建立网络流(NetStream)的函数 rtmpdump源代码

Kafka SocketServer源代码分析

Kafka SocketServer源代码分析 标签: kafka 本文将详细分析Kafka SocketServer的相关源码. 总体设计 Kafka SocketServer是基于Java NIO来开发的,采用了Reactor的模式,其中包含了1个Acceptor负责接受客户端请求,N个Processor负责读写数据,M个Handler来处理业务逻辑.在Acceptor和Processor,Processor和Handler之间都有队列来缓冲请求. kafka.network.Accepto

Jafka源代码分析——随笔

Kafka是一个分布式的消息中间件,可以粗略的将其划分为三部分:Producer.Broker和Consumer.其中,Producer负责产生消息并负责将消息发送给Kafka:Broker可以简单的理解为Kafka集群中的每一台机器,其负责完成消息队列的主要功能(接收消息.消息的持久化存储.为Consumer提供消息.消息清理.....):Consumer从Broker获取消息并进行后续的操作.每个broker会有一个ID标识,该标识由人工在配置文件中配置. Kafka中的消息隶属于topic

ftp server源代码分析20140602

当前是有些工具比如apktool,dextojar等是可以对我们android安装包进行反编译,获得源码的.为了减少被别人破解,导致源码泄露,程序被别人盗取代码,等等.我们需要对代码进行混淆,android的sdk中为我们提供了ProGrard这个工具,可以对代码进行混淆(一般是用无意义的名字来重命名),以及去除没有使用到的代码,对程序进行优化和压缩,这样可以增加你想的难度.最近我做的项目,是我去配置的混淆配置,因此研究了一下,这里分享一下. 如何启用ProGuard ant项目和eclipse

Spark SQL之External DataSource外部数据源(二)源代码分析

上周Spark1.2刚公布,周末在家没事,把这个特性给了解一下,顺便分析下源代码,看一看这个特性是怎样设计及实现的. /** Spark SQL源代码分析系列文章*/ (Ps: External DataSource使用篇地址:Spark SQL之External DataSource外部数据源(一)演示样例 http://blog.csdn.net/oopsoom/article/details/42061077) 一.Sources包核心 Spark SQL在Spark1.2中提供了Exte

【转载】linux环境下tcpdump源代码分析

linux环境下tcpdump源代码分析 原文时间 2013-10-11 13:13:02   原文链接   主题 Tcpdump 作者:韩大卫 @ 吉林师范大学 tcpdump.c 是tcpdump 工具的main.c, 本文旨对tcpdump的框架有简单了解,只展示linux平台使用的一部分核心代码. Tcpdump 的使用目的就是打印出指定条件的报文,即使有再多的正则表达式作为过滤条件.所以只要懂得tcpdump -nXXi eth0 的实现原理即可. 进入main之前,先看一些头文件 n

Android万能适配器base-adapter-helper的源代码分析

项目地址:https://github.com/JoanZapata/base-adapter-helper 1. 功能介绍 1.1. base-adapter-helper base-adapter-helper 是对传统的 BaseAdapter ViewHolder 模式的一个封装.主要功能就是简化我们书写 AbsListView 的 Adapter 的代码,如 ListView,GridView. 1.2 基本使用 mListView.setAdapter(mAdapter = new

UiAutomator喷射事件的源代码分析

上一篇文章<UiAutomator源代码分析之UiAutomatorBridge框架>中我们把UiAutomatorBridge以及它相关的类进行的描写叙述,往下我们会尝试依据两个实例将这些类给串联起来,我准备做的是用例如以下两个非常有代表性的实例: 注入事件 获取控件 这一篇文章我们会通过分析UiDevice的pressHome这种方法来分析UiAutomator是怎样注入事件的,下一篇文章会描写叙述怎样获取控件,敬请期待. 1. UiObject.pressHome顺序图 首先我们看一下我