.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) };
};

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

   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');
}
};

   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;
}
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;

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

     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;
};

  二、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+, ii-im-);
//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 连接

     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",.........]” 到客户端

    

    

.net , java webSocket 连接 Socket.io (1.4.4版本) 问题的更多相关文章

  1. AndroidAsync :异步Socket,http(client+server),websocket和socket.io的Android类库

    AndroidAsync是一个用于Android应用的异步Socket,http(client+server),websocket和socket.io的类库.基于NIO,没有线程.它使用java.ni ...

  2. 即时通信WebSocket 和Socket.IO

    WebSocket HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯. 在2008年诞生,2011年成为国际标准. 现在基本所有浏览器都已经支持了. We ...

  3. websocket与socket.io

    什么是Websocket? Websocket是一个独立于http的实时通信协议,最初是在HTML5中被引用进来的,在HTML5规范中作为浏览器与服务器的核心通信技术被嵌入到浏览器中.WebSocke ...

  4. 长连接 Socket.IO

    概念 说到长连接,对应的就是短连接了.下面先说明一下长连接和短连接的区别: 短连接与长连接 通俗来讲,浏览器和服务器每进行一次通信,就建立一次连接,任务结束就中断连接,即短连接.相反地,假如通信结束( ...

  5. websocket 与Socket.IO介绍

    一  websocket WebSocket是html5新增加的一种通信协议,目前流行的浏览器都支持这个协议,例如 Chrome,Safrie,Firefox,Opera,IE等等,对该协议支持最早的 ...

  6. websocket 和 socket.io 之间的区别是什么

    socket.io封装了websocket,同时包含了其它的连接方式,比如Ajax.原因在于不是所有的浏览器都支持websocket,通过socket.io的封装,你不用关心里面用了什么连接方式.你在 ...

  7. websocket 和 socket.io 之间的区别

    socket.io封装了websocket,同时包含了其它的连接方式,比如Ajax.原因在于不是所有的浏览器都支持websocket,通过socket.io的封装,你不用关心里面用了什么连接方式.你在 ...

  8. 轮询以及webSocket与socket.io原理

    概述: 首先,我们知道,起初的http协议只是为了能够进行通信而被创造出来(也就是请求-响应的过程).并没有双向通信这一说,后面随着历史业务的需求,人们使用轮询http来解决双向通信也就是使用xhr或 ...

  9. Socket.io在线聊天室

    从零开始nodejs系列文章,将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发.Nodejs框架是基于V8的引擎,是目前速度最快的Javascript引擎.chrome浏 ...

随机推荐

  1. An incompatible version 1.1.14 of APR based Apache Tomcat Native library is installed, while Tomcat

    启动tomcat 7.0, 看到日志里出现严重警告, An incompatible version 1.1.14 of APR based Apache Tomcat Native library ...

  2. [Angular] AfterContentChecked && AfterViewChecked

    AfterContentChecked & AfterViewChecked are called after 'OnChanges' lifecycle. And each time 'ng ...

  3. JVM性能调优监控工具jps、jstack、jmap、jhat、jstat等使用详解

    转载:http://blog.csdn.net/tzs_1041218129/article/details/61630981 javap 和 javac javap -help javac -hel ...

  4. SQL Server中按照条件随机返回数据

    需求:查询对应关键字的数据,并随机返回一条. 这时,需要一个SQL的那只方法:NEWID(). 用法: [sql]SELECT TOP 1 * FROM Table WHERE TID = 1 ORD ...

  5. mysql中,由于JDBC连接限制了最大包长度1024B,即1KB,报错“max_allowed_packet' ”

    报错:org.springframework.dao.TransientDataAccessResourceException: PreparedStatementCallback; SQL [INS ...

  6. vue - config(dev.env.js和prov.env.js)

    描述:配置产品模式.打包模式:开发还是打包,以最佳运行(不配置则有一个大大的Warning!!!) 官网:https://www.webpackjs.com/concepts/mode/

  7. 分布式消息系统Jafka入门指南

    分布式消息系统Jafka入门指南 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs 一.JafkaMQ简单介绍 JafkaMQ是一个分布式的公布/订阅消息系 ...

  8. 字符串在内存中的存储——C语言进阶

    字符串是以ASCII字符NUL结尾的字符序列. ASCII字符NUL表示为\0.字符串通常存储在数组或者从堆上分配的内存中.只是,并不是全部的字符数组都是字符串,字符数组可能没有NUL字符. 字符数组 ...

  9. Google 地图 API for Android

    原文:Introduction to Google Maps API for Android 作者:Eunice Obugyei 译者:kmyhy 从健康类 app Runkeeper 到游戏 app ...

  10. C#创建COM组件供VB,PB,Delphi调用

    1  COM组件概述 COM是微软公司为了计算机工业的软件生产更加符合人类的行为方式开发的一种新的软件开发技术.在COM构架下,人们可以开发出各种各样的功能专一的组件,然后将它们按照需要组合起来,构成 ...