.net , java webSocket 连接 Socket.io (1.4.4版本) 问题

jopen 8年前

.net版Socketio4net类库和java版socket.io-java-client类库 连接socket.io 1.4版本都不行,网上大多是socket.io 0.9版本的,socket.io 更新之后就不支持了。本人已研究

成功连接socket.io 1.4版本的方法,例子采用C#。

一、socket.io 几个重要要文件

1、node_modules\socket.io\node_modules\engine.io\node_modules\engine.io-parser\lib\index.js

var packets = exports.packets = {      open:     0    // non-ws    , close:    1    // non-ws    , ping:     2    , pong:     3    , message:  4    , upgrade:  5    , noop:     6  };

这几个是定义消息类型的 websocket连接的时候在open事件里需要发送一个send("5[\"simple\",{\"name\":\"simple\"}]"); 类型为5的消息。

 exports.decodePacket = function (data, binaryType, utf8decode) {    // String data     console.log('解析数据'+data);    if (typeof data == 'string' || data === undefined) {      if (data.charAt(0) == 'b') {        return exports.decodeBase64Packet(data.substr(1), binaryType);      }        var type = data.charAt(0);             if (utf8decode) {        try {          data = utf8.decode(data);        } catch (e) {          return err;        }      }      console.log('解析数据3:'+type);      if (Number(type) != type || !packetslist[type]) {        return err;      }        if (data.length > 1) {        return { type: packetslist[type], data: data.substring(1) };      } else {        return { type: packetslist[type] };      }    }      // Binary data    if (binaryType === 'arraybuffer') {      var type = data[0];      var intArray = new Uint8Array(data.length - 1);      for (var i = 1; i < data.length; i++) {        intArray[i - 1] = data[i];      }      return { type: packetslist[type], data: intArray.buffer };    }    var type = data[0];    return { type: packetslist[type], data: data.slice(1) };  };    View Code

从客户端发过来的消息会从这里解析出来,得到消息类型。

2、node_modules\socket.io\node_modules\engine.io\lib\socket.js

从上面解析出来的消息字符串会到这里

 Socket.prototype.onPacket = function (packet) {      console.log('engine.io-lib-Socket.js==OnPacket///'+packet);    if ('open' == this.readyState) {      // export packet event      debug('packet');      this.emit('packet', packet);        // Reset ping timeout on any packet, incoming data is a good sign of      // other side's liveness      this.setPingTimeout();      console.log('engine.io-lib-Socket.js==OnPacket>>>'+packet.type);//upgrade      switch (packet.type) {          case 'ping':          debug('got ping');          this.sendPacket('pong');          this.emit('heartbeat');          break;          case 'error':          this.onClose('parse error');          break;          case 'message':          this.emit('data', packet.data);          this.emit('message', packet.data);          break;      }    } else {      debug('packet received with closed socket');      console.log('packet received with closed socket');    }  };    View Code

3、node_modules\socket.io\node_modules\socket.io-parser\index.js

 function decodeString(str) {      console.log('socket.io-parser-index.js-encodeAsString4---'+str);    var p = {};    var i = 0;      // look up type    p.type = Number(str.charAt(0));    if (null == exports.types[p.type]) return error();      // look up attachments if type binary    if (exports.BINARY_EVENT == p.type || exports.BINARY_ACK == p.type) {       console.log("---------1");      var buf = '';      while (str.charAt(++i) != '-') {        buf += str.charAt(i);        if (i == str.length) break;      }      if (buf != Number(buf) || str.charAt(i) != '-') {        throw new Error('Illegal attachments');      }      p.attachments = Number(buf);    }        // look up namespace (if any)    if ('/' == str.charAt(i + 1)) {      p.nsp = '';      while (++i) {        var c = str.charAt(i);        if (',' == c) break;        p.nsp += c;        if (i == str.length) break;      }    } else {      p.nsp = '/';    }      // look up id    var next = str.charAt(i + 1);    if ('' !== next && Number(next) == next) {      p.id = '';      while (++i) {        var c = str.charAt(i);        if (null == c || Number(c) != c) {          --i;          break;        }        p.id += str.charAt(i);        if (i == str.length) break;      }      p.id = Number(p.id);    }      // look up json data    if (str.charAt(++i)) {      try {        console.log("---------21/"+str.substr(i));        p.data = json.parse(str.substr(i));      } catch(e){        return error();      }    }    console.log(p);    debug('decoded %s as %j', str, p);    return p;  }    View Code
 exports.types = [    'CONNECT',    'DISCONNECT',    'EVENT',    'ACK',    'ERROR',    'BINARY_EVENT',    'BINARY_ACK'  ];    /**   * Packet type `connect`.   *   * @api public   */    exports.CONNECT = 0;    /**   * Packet type `disconnect`.   *   * @api public   */    exports.DISCONNECT = 1;    /**   * Packet type `event`.   *   * @api public   */    exports.EVENT = 2;    /**   * Packet type `ack`.   *   * @api public   */    exports.ACK = 3;    /**   * Packet type `error`.   *   * @api public   */    exports.ERROR = 4;    /**   * Packet type 'binary event'   *   * @api public   */    exports.BINARY_EVENT = 5;    /**   * Packet type `binary ack`. For acks with binary arguments.   *   * @api public   */    exports.BINARY_ACK = 6;    View Code

然后消息会传递到这里,再解析它。

4、node_modules\socket.io\node_modules\socket.io-parser\node_modules\component-emitter\index.js

最后消息会到这里找到对应的回调函数。

 Emitter.prototype.emit = function(event){         // console.log(arguments);   //  console.log("event");    //console.log(event);    // console.log("_callbacks");    // console.log( this._callbacks);    this._callbacks = this._callbacks || {};    var args = [].slice.call(arguments, 1)      , callbacks = this._callbacks[event];      //console.log('args');      //console.log(args);      //console.log('callbacks');          if (callbacks) {       //  console.log('回调 正确');      callbacks = callbacks.slice(0);            console.log(callbacks);      for (var i = 0, len = callbacks.length; i < len; ++i) {        callbacks[i].apply(this, args);         // console.log('执行 正确');      }    }    else    {        console.log('回调 出错');    }      return this;  };    View Code

二、socket.io授权

1、.net授权获取sid

授权地址http://127.0.0.1:3000/socket.io/?eio=3&transport=polling&t=1404421022936,0.9版本的socket.io授权不一样,通过这个授权地址返回

sessionid,如下格式 0{"sid":"BrB2vsiK79ZoLdMcAAAK","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":60000},解析得到sid.

 protected SocketIOHandshake requestHandshake(Uri uri)          {              string value = string.Empty;              string errorText = string.Empty;              SocketIOHandshake handshake = null;                using (WebClient client = new WebClient())              {                   try                  {                      client.Headers.Add("cookie:io=3435456567567567355");                     // client.Headers.Add("cookie:express.sid=3435456567567567355");                      //client.Headers.Add("cookie:sid=3435456567567567355");                      value = client.DownloadString("http://127.0.0.1:3000/socket.io/?eio=3&transport=polling&t=1404421022936");                      int ii = value.IndexOf("\",");                      int im = value.IndexOf("\":\"");                      value = value.Substring(im+3, ii-im-3);                      //value = "3435456567567567355";                      //value = client.DownloadString(string.Format("{0}://{1}:{2}/socket.io/1/{3}", uri.Scheme, uri.Host, uri.Port, uri.Query)); // #5 tkiley: The uri.Query is available in socket.io's handshakeData object during authorization                      value = value+":55000:60000:websocket";                      if (string.IsNullOrEmpty(value))                          errorText = "Did not receive handshake string from server";                  }                  catch (Exception ex)                  {                      errorText = string.Format("Error getting handsake from Socket.IO host instance: {0}", ex.Message);                      //this.OnErrorEvent(this, new ErrorEventArgs(errMsg));                  }              }              if (string.IsNullOrEmpty(errorText))                  handshake = SocketIOHandshake.LoadFromString(value);              else              {                  handshake = new SocketIOHandshake();                  handshake.ErrorMessage = errorText;              }                return handshake;          }    View Code

以下是socket.io接收到的授权消息,能够取到客户端传来的cookie,可以用过控制重复登录。

 io.set('authorization', function(handshakeData, callback) {      // callback(handshakeData, true);           callback(null, true);      return      if (handshakeData.headers.cookie) {          //console.log(handshakeData.headers.cookie);          handshakeData.cookie = cookie.parse(handshakeData.headers.cookie);          //console.log(handshakeData.cookie);          handshakeData.cookie['express.sid']=handshakeData.cookie.io;          handshakeData.sessionID = handshakeData.cookie['express.sid'];          //console.log(handshakeData.sessionID);          //console.log(handshakeData.cookie['express.sid']);                    console.log("handshakeData:" + handshakeData.headers.cookie + "-----" + handshakeData.cookie);                //var connect_sid = handshakeData.cookie['connect.sid'];          //console.log("connect_sid="+connect_sid);          handshakeData.session = handshakeData.sessionID;          if (handshakeData.cookie['express.sid'] == handshakeData.sessionID) {            console.log('1-true');            return callback(null, true);          }          //return callback('Cookie is invalid.', false);      }       else {          console.log('12-err');          //return callback('No cookie transmitted.', false);      }       });    View Code

三、websocket 连接

websocket连接地址ws://127.0.0.1:3000/socket.io/?eio=3&t=124324324324&transport=websocket&sid=" + this.HandShake.SID,这个很重要

 public void Connect()          {              lock (padLock)              {                  if (!(this.ReadyState == WebSocketState.Connecting || this.ReadyState == WebSocketState.Open))                  {                      try                      {                          this.ConnectionOpenEvent.Reset();                          this.HandShake = this.requestHandshake(uri);// perform an initial HTTP request as a new, non-handshaken connection                            if (this.HandShake == null || string.IsNullOrWhiteSpace(this.HandShake.SID) || this.HandShake.HadError)                          {                              this.LastErrorMessage = string.Format("Error initializing handshake with {0}", uri.ToString());                              this.OnErrorEvent(this, new ErrorEventArgs(this.LastErrorMessage, new Exception()));                          }                          else                          {                              String sss = "ws://127.0.0.1:3000/socket.io/?eio=3&t=124324324324&transport=websocket&sid=" + this.HandShake.SID;                              //sss = "ws://127.0.0.1:3000/socket.io/?transport=polling&t=12434324324324&sid=" + this.HandShake.SID;                              //string.Format("{0}://{1}:{2}/socket.io/1/websocket/{3}", wsScheme, uri.Host, uri.Port, this.HandShake.SID)                              string wsScheme = (uri.Scheme == Uri.UriSchemeHttps ? "wss" : "ws");                              this.wsClient = new WebSocket(                                  sss,                                  string.Empty,                                  this.socketVersion);                              this.wsClient.EnableAutoSendPing = false; // #4 tkiley: Websocket4net client library initiates a websocket heartbeat, causes delivery problems                              this.wsClient.Opened += this.wsClient_OpenEvent;                              this.wsClient.MessageReceived += this.wsClient_MessageReceived;                              this.wsClient.Error += this.wsClient_Error;                                this.wsClient.Closed += wsClient_Closed;                                this.wsClient.Open();                          }                      }                      catch (Exception ex)                      {                          Trace.WriteLine(string.Format("Connect threw an exception...{0}", ex.Message));                          this.OnErrorEvent(this, new ErrorEventArgs("SocketIO.Client.Connect threw an exception", ex));                      }                  }              }          }    View Code

连接之后在open 事件里需要发送一个类型为5(upgrade)的消息websocket.send("5[\"simple\",{\"name\":\"simple\"}]");,然后websocket会收到一个“40”消息,

40代表连接功能了,可以进行通信了。

一般发送消息的格式为:"42[\"simple\",{\"name\":\"tstssss\"}]"

42:代表消息类型,simple为socket.io的事件名称。

来自: http://www.cnblogs.com/netuml/p/5141345.html