.net版Socketio4net類庫和java版socket.io-java-client類庫 鏈接socket.io 1.4版本都不行,網上大可能是socket.io 0.9版本的,socket.io 更新以後就不支持了。本人已研究java
成功鏈接socket.io 1.4版本的方法,例子採用C#。node
一、node_modules\socket.io\node_modules\engine.io\node_modules\engine.io-parser\lib\index.js web
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的消息。express
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) }; };
從客戶端發過來的消息會從這裏解析出來,獲得消息類型。json
二、node_modules\socket.io\node_modules\engine.io\lib\socket.jsapi
從上面解析出來的消息字符串會到這裏服務器
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'); } };
三、node_modules\socket.io\node_modules\socket.io-parser\index.jswebsocket
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; }
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;
而後消息會傳遞到這裏,再解析它。cookie
四、node_modules\socket.io\node_modules\socket.io-parser\node_modules\component-emitter\index.jssession
最後消息會到這裏找到對應的回調函數。
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; };
一、.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; }
如下是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); } });
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)); } } } }
鏈接以後在open 事件裏須要發送一個類型爲5(upgrade 心跳)的消息websocket.send("5[\"simple\",{\"name\":\"simple\"}]");,而後websocket會收到一個「40」消息,
40表明鏈接功能了,能夠進行通訊了。
通常發送消息的格式爲:"42[\"simple\",{\"name\":\"tstssss\"}]"
42:表明消息類型,simple爲socket.io的事件名稱。
受權的時候能獲取到"pingInterval":25000,"pingTimeout":60000 心跳間隔和超時的時間,須要每隔 pingInterval 時間 發送一次心跳數據才能保存不斷開鏈接。
send("5:::");
服務器回調:
socket.io 服務器端給客戶端發送數據帶回調函數以下:
socket.emit('newuser','newuser-data',function(m,d){ console.log(m); console.log(d); });
客戶端接收到的數據形式以下: 420["newuser","newuser-data"] 或 4290203["newuser","newuser-data"]
其中4表明:message,2表明:event ,0 ,90203 表明:回調函數的事件ID號,事件ID號是不固定的
若是客戶端收到消息,服務器須要觸發回調函數時:
this.send("430[\"newuser\",{\"name\":\"simple\"}]");
this.send("4390203[\"newuser\",{\"name\":\"simple\"}]");
其中 3表明:ack 回調, 「newuser」必須和原有名字一致。
客戶端回調:
socket.on('messageAck', function (data,fn) { console.log(data); //console.log(fn); fn('aaa','bb','cc',{id:1}); });
客戶端發送 this.send("423[\"messageAck\",\"ssssssssssssssssss\"]"); ,3 表明消息ID
服務器收到信息以後 回立馬發送 「433["messageAck",.........]」 到客戶端