SOCKET.IO,IO=MANAGER(SOURCE, OPTS)

原文:http://www.cnblogs.com/xiezhengcai/p/3968067.html

当我们在使用

var socket = io("ws://103.31.201.154:5555");

的时候,socket.io都做了什么呢?建立socket连接,嗯 不错,但是我们还是得看看它是怎么实现的。

其实在socket.io里,io函数就是Manager函数,而Manager函数返回的就是Manager对象

复制代码
function Manager(uri, opts){
    //返回Manager对象
  if (!(this instanceof Manager)) return new Manager(uri, opts);
  if (uri && ('object' == typeof uri)) {
    opts = uri;
    uri = undefined;
  }
  opts = opts || {};
  opts.path = opts.path || '/socket.io';
  this.nsps = {};
//所有订阅socket状态的容器
  this.subs = [];
  this.opts = opts;
  //是否重连
  this.reconnection(opts.reconnection !== false);
  //最大重连次数
  this.reconnectionAttempts(opts.reconnectionAttempts || Infinity);
  //两次重连之间的延迟
  this.reconnectionDelay(opts.reconnectionDelay || 1000);
  //两次重连之间的最大延迟
  this.reconnectionDelayMax(opts.reconnectionDelayMax || 5000);
  //connection超时时间
  this.timeout(null == opts.timeout ? 20000 : opts.timeout);
  //连接状态
  this.readyState = 'closed';
  this.uri = uri;
  //重连数
  this.connected = 0;
  //尝试次数
  this.attempts = 0;
  //与engine.io数据交互时数据要编码
  this.encoding = false;
// packetBuffer
  this.packetBuffer = [];
  this.encoder = new parser.Encoder();
  this.decoder = new parser.Decoder();
  //是否自动连接
  this.autoConnect = opts.autoConnect !== false;
  //如果自动连接则开始连接
  if (this.autoConnect) this.open();
}
复制代码

代码中的注释已经很清楚了,但是值得一提的manager是对engine.io的一层封装,从客户端代码来看,在engine.io的基础上实现 自动重连机制。另外值得注意的是encoding、packetBuffer俩变量,当向engine.io传递数据时,我们要对数据进行encode,所以encoding是表示是否在对数据进行encode中,因为encoding是调用engine.io下的.write函数,同时也看出来,engine.io是socket.io的数据传输层。当数据在encode中时,encoding=true,如果当前正在encode中,那么新的数据就会被缓存到packetBuffer里,当encode结束会自动在packetBuffer里遍历进行encode(代码2)。另外subs数组装的是清除所有订阅socket状态的容器,如(代码1):

代码1

//清除socket连接超时计时器   
 this.subs.push({
      destroy: function(){
        clearTimeout(timer);
      }
    });

代码2

复制代码
Manager.prototype.packet = function(packet){
  debug('writing packet %j', packet);
  var self = this;
  if (!self.encoding) {
    // encode,encoding标识为true
    self.encoding = true;
    this.encoder.encode(packet, function(encodedPackets) {
      for (var i = 0; i < encodedPackets.length; i++) {
        self.engine.write(encodedPackets[i]);
      }
      //encode结束,encoding置为false
      self.encoding = false;
      //查询队列执行packet
      self.processPacketQueue();
    });
  } else { //如果在encode中,push到Buffer里
    self.packetBuffer.push(packet);
  }
};
复制代码

在Manager的构造函数里,最后的结果是调用了open函数,这是打开socket连接的入口

复制代码
Manager.prototype.open =
Manager.prototype.connect = function(fn){
  debug('readyState %s', this.readyState);
  //如果已经打开,直接返回
  if (~this.readyState.indexOf('open')) return this;

  debug('opening %s', this.uri);
  //打开socket连接
  this.engine = eio(this.uri, this.opts);
  var socket = this.engine;
  var self = this;
  this.readyState = 'opening';

  // emit `open`
  var openSub = on(socket, 'open', function() {
    self.onopen();
    fn && fn();
  });

  // emit `connect_error`
  var errorSub = on(socket, 'error', function(data){
    debug('connect_error');
    self.cleanup();
    self.readyState = 'closed';
    self.emitAll('connect_error', data);
    if (fn) {
      var err = new Error('Connection error');
      err.data = data;
      fn(err);
    }

    self.maybeReconnectOnOpen();
  });

  if (false !== this._timeout) {
    var timeout = this._timeout;
    debug('connect attempt will timeout after %d', timeout);

    // 设置连接超时
    var timer = setTimeout(function(){
      debug('connect attempt timed out after %d', timeout);
      openSub.destroy();
      socket.close();
      socket.emit('error', 'timeout');
      self.emitAll('connect_timeout', timeout);
    }, timeout);

    this.subs.push({
      destroy: function(){
        clearTimeout(timer);
      }
    });
  }

  this.subs.push(openSub);
  this.subs.push(errorSub);
    //返回Manager实例(已经打开socket连接的)
  return this;
};
复制代码

相信熟悉之前的代码后,阅读这部分代码轻松也很容易,通过engine.io打开socket连接,同时将readyState置于opening状态,也监听socket连接的状态信息,和刚才讲的一样,将清除监听放在subs容其中,在后续的代码可以看到有cleanup来执行容器里面的所有函数。这就不细讲了。

知识是我们已知的 也是我们未知的 基于已有的知识之上 我们去发现未知的 由此,知识得到扩充 我们获得的知识越多 未知的知识就会更多 因而,知识扩充永无止境