长联网解决方案
JWebSocket
JWebSocket是JEngine提供的对websocket后端建立长连接的解决方案
与node.js
的socket-io v2
完美兼容
提示
如果后端使用socket-io
,请确保使用的版本是v2.x
,或者自行修改JWebSocket建立连接部分源码
命名空间
using JEngine.Net;
配置
public class JSocketConfig
{
public bool debug = false;
public bool autoConnect = false;
public int reconnectDelay = 5;
public float ackExpirationTime = 30f;
public float pingInterval = 25f;
public float pingTimeout = 60f;
public string eventOpenName = "open";
public string eventConnectName = "connect";
public string eventDisconnectName = "disconnect";
public string eventErrorName = "error";
public string eventCloseName = "close";
public static JSocketConfig Default()
{
return new JSocketConfig();
}
}
配置内按以下顺序定义了:
- 是否调试(显示报错)
- 是否自动重连
- 自动重连间隔
- 发的包的过期时间(仅限socketio)
- ping间隔
- ping超时
- open事件名
- connect事件名
- disconnect事件名
- error事件名
- close事件名
- 默认配置
接口
初始化
/// <summary>
/// 连接websokcet服务器,如果使用的socket-io,请给isSocketIO参数设置为true(socketio是nodejs服务器使用的一个websocket插件)
/// </summary>
/// <param name="url"></param>
/// <param name="config"></param>
/// <param name="isSocketIO"></param>
public JWebSocket(string url,JSocketConfig config = null,Action<object,MessageEventArgs> OnMessage = null)
OnMessage是收到消息后的处理回调,socketio服务端这里可以为null,反之必须写回调,不然收到消息也没办法处理
连接
/// <summary>
/// Connect to server, this method doesn't block the context
/// 连接服务器,此方法不阻塞
/// </summary>
public void Connect()
设置回调相关接口(仅限非socket-io服务端)
public void OnOpen(Action<SocketIOEvent> socketIOEvent)
public void OnConnect(Action<SocketIOEvent> socketIOEvent)
public void OnReconnect(Action socketIOEvent)
public void OnDisconnect(Action<SocketIOEvent> socketIOEvent)
public void OnClose(Action<SocketIOEvent> socketIOEvent)
public void OnError(Action<SocketIOEvent> socketIOEvent)
设置回调相关接口(仅限socket-io服务端)
public void SocketIO_On(string eventName, Action<SocketIOEvent> socketIOEvent)
public void SocketIO_Off(string eventName, Action<SocketIOEvent> socketIOEvent)
发送信息(仅限非socket-io服务端)
public void SendToServer(string Data)
public void SendToServerAsJson<T>(T Data)
public void SendToServerAsProtobuf<T>(T Data) where T : class
public void SendToServer(byte[] Data)
按顺序依次是:发字符串,发json字符串,发protobuf二进制,发二进制
发送信息(仅限socket-io服务端)
这里的ev是事件名
/// <summary>
/// Call event on server (only for socket-io servers, eg. nodeJS servers that uses socket-io)
/// 调用服务端事件(只有使用socket-io搭建的服务器才能使用该接口,比如nodeJS使用socket-io的服务器)
/// </summary>
/// <param name="ev"></param>
public void EmitToSocketIOServer(string ev)
/// <summary>
/// Call event on server (only for socket-io servers, eg. nodeJS servers that uses socket-io)
/// 调用服务端事件(只有使用socket-io搭建的服务器才能使用该接口,比如nodeJS使用socket-io的服务器)
/// </summary>
/// <param name="ev"></param>
/// <param name="onComplete">异步并行回调</param>
public void EmitToSocketIOServerAsync(string ev, Action<bool> onComplete)
/// <summary>
/// Call event on server (only for socket-io servers, eg. nodeJS servers that uses socket-io)
/// 调用服务端事件(只有使用socket-io搭建的服务器才能使用该接口,比如nodeJS使用socket-io的服务器)
/// </summary>
/// <param name="ev"></param>
/// /// <returns>发送结果 emit result</returns>
public async Task<bool> EmitToSocketIOServerAsync(string ev)
/// <summary>
/// Call event on server with a call back (only for socket-io servers, eg. nodeJS servers that uses socket-io)
/// 调用服务端事件,并包含一个回调(只有使用socket-io搭建的服务器才能使用该接口,比如nodeJS使用socket-io的服务器)
/// </summary>
/// <param name="ev"></param>
/// <param name="action">回调 callback</param>
public void EmitToSocketIOServer(string ev, Action<JSONObject> action)
/// <summary>
/// Call event on server with a call back (only for socket-io servers, eg. nodeJS servers that uses socket-io)
/// 调用服务端事件,并包含一个回调(只有使用socket-io搭建的服务器才能使用该接口,比如nodeJS使用socket-io的服务器)
/// </summary>
/// <param name="ev"></param>
/// <param name="action">回调 callback</param>
/// <param name="onComplete">异步并行回调</param>
public void EmitToSocketIOServerAsync(string ev, Action<JSONObject> action, Action<bool> onComplete)
/// <summary>
/// Call event on server with a call back (only for socket-io servers, eg. nodeJS servers that uses socket-io)
/// 调用服务端事件,并包含一个回调(只有使用socket-io搭建的服务器才能使用该接口,比如nodeJS使用socket-io的服务器)
/// </summary>
/// <param name="ev"></param>
/// <param name="action">回调 callback</param>
/// <returns>发送结果 emit result</returns>
public async Task<bool> EmitToSocketIOServerAsync(string ev, Action<JSONObject> action)
/// <summary>
/// Call event on server with a string (only for socket-io servers, eg. nodeJS servers that uses socket-io)
/// 调用服务端事件,并发送个字符串(只有使用socket-io搭建的服务器才能使用该接口,比如nodeJS使用socket-io的服务器)
/// </summary>
/// <param name="ev">事件名字 event name</param>
/// <param name="str">字符串 string</param>
public void EmitToSocketIOServer(string ev, string str)
/// <summary>
/// Call event on server (only for socket-io servers, eg. nodeJS servers that uses socket-io)
/// 调用服务端事件,并发送个字符串(只有使用socket-io搭建的服务器才能使用该接口,比如nodeJS使用socket-io的服务器)
/// </summary>
/// <param name="ev">事件名字 event name</param>
/// /// <param name="str">字符串 string</param>
/// <param name="onComplete">异步并行回调</param>
public void EmitToSocketIOServerAsync(string ev, string str, Action<bool> onComplete)
/// <summary>
/// Call event on server (only for socket-io servers, eg. nodeJS servers that uses socket-io)
/// 调用服务端事件,并发送个字符串(只有使用socket-io搭建的服务器才能使用该接口,比如nodeJS使用socket-io的服务器)
/// </summary>
/// <param name="ev">事件名字 event name</param>
/// /// <param name="str">字符串 string</param>
/// <returns>发送结果 emit result</returns>
public async Task<bool> EmitToSocketIOServerAsync(string ev, string str)
/// <summary>
/// Call event on server with a json data (only for socket-io servers, eg. nodeJS servers that uses socket-io)
/// 调用服务端事件,并发送个JSON数据(只有使用socket-io搭建的服务器才能使用该接口,比如nodeJS使用socket-io的服务器)
/// </summary>
/// <param name="ev">事件名字 event name</param>
/// <param name="data">json数据 json data</param>
public void EmitToSocketIOServer(string ev, JSONObject data)
/// <summary>
/// Call event on server (only for socket-io servers, eg. nodeJS servers that uses socket-io)
/// 调用服务端事件,并发送个JSON数据(只有使用socket-io搭建的服务器才能使用该接口,比如nodeJS使用socket-io的服务器)
/// </summary>
/// <param name="ev">事件名字 event name</param>
/// <param name="data">json数据 json data</param>
/// <param name="onComplete">异步并行回调</param>
public void EmitToSocketIOServerAsync(string ev, JSONObject data, Action<bool> onComplete)
/// <summary>
/// Call event on server (only for socket-io servers, eg. nodeJS servers that uses socket-io)
/// 调用服务端事件,并发送个JSON数据(只有使用socket-io搭建的服务器才能使用该接口,比如nodeJS使用socket-io的服务器)
/// </summary>
/// <param name="ev">事件名字 event name</param>
/// <param name="data">json数据 json data</param>
/// <param name="action">回调 callback</param>
/// <returns>发送结果 emit result</returns>
public async Task<bool> EmitToSocketIOServerAsync(string ev, JSONObject data)
/// <summary>
/// Call event on server with a json data and a callback(only for socket-io servers, eg. nodeJS servers that uses socket-io)
/// 调用服务端事件,发送JSON数据且包含回调(只有使用socket-io搭建的服务器才能使用该接口,比如nodeJS使用socket-io的服务器)
/// </summary>
/// <param name="ev">事件名字 event name</param>
/// <param name="data">json数据 json data</param>
/// <param name="action">回调 callback</param>
public void EmitToSocketIOServer(string ev, JSONObject data, Action<JSONObject> action)
/// <summary>
/// Call event on server (only for socket-io servers, eg. nodeJS servers that uses socket-io)
/// 调用服务端事件,发送JSON数据且包含回调(只有使用socket-io搭建的服务器才能使用该接口,比如nodeJS使用socket-io的服务器)
/// </summary>
/// <param name="ev">事件名字 event name</param>
/// <param name="data">json数据 json data</param>
/// <param name="action">回调 callback</param>
/// <param name="onComplete">异步并行回调</param>
public void EmitToSocketIOServerAsync(string ev, JSONObject data, Action<JSONObject> action, Action<bool> onComplete)
/// <summary>
/// Call event on server (only for socket-io servers, eg. nodeJS servers that uses socket-io)
/// 调用服务端事件,发送JSON数据且包含回调(只有使用socket-io搭建的服务器才能使用该接口,比如nodeJS使用socket-io的服务器)
/// </summary>
/// <param name="ev">事件名字 event name</param>
/// <param name="data">json数据 json data</param>
/// <param name="action">回调 callback</param>
/// <returns>发送结果 emit result</returns>
public async Task<bool> EmitToSocketIOServerAsync(string ev, JSONObject data, Action<JSONObject> action)
注意事项
- 连接其他web socket服务器,需要自己实现on方法,在OnMessageFromNormalServer方法内根据自己的消息模型自己实现。
- 连接普通WebSocket服务器的方法监听,建议有服务器基础,且C#有经验的人去写监听,没经验的,也可以用这个做发送,但是监听这边会很麻烦
示范服务端
地址:https://github.com/JasonXuDeveloper/JEngine-WebSocket-Server-Demo
使用示范
using System;
using JEngine.Core;
using JEngine.Net;
using WebSocketSharp;
namespace JEngine.Examples
{
public class JWebSocketDemo
{
/// <summary>
/// 接收服务器消息的方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void OnMessageFromNormalServer(object sender, MessageEventArgs e)
{
Log.Print("服务端发送了:" + e.Data);//二进制是e.RawData
/*在这里给个具体思路
* 例如目前封装的socket io的消息模型
* socketio采用的是json封装,包含了event name,event type 和 event data(这个在socket io 的packer里)
* event name 顾名思义是事件名称
* event type 这个可以忽略,就是事件类型,普遍是message
* event data 是数据的json格式
* 会返回一个JSONObject,然后可以根据这个JSONObject做你的逻辑
*
* 所以这里的思路是你也封装一个这样的模型,然后写个字典来存事件
* 以socket io 为例,先解析e.Data,得到字符串:event name,JSONObject:event data
* 然后直接在Dictionary<string,Action<JSONObject>>的字典里,获取event name这个值
* 如果存在,Invoke(data),通过数据去Invoke回调
* 然后没然后了,别在群里问JWebSocket非socket io 服务器怎么事件派发无效了,
* 因为你们要自己按项目定模型,自己写的,JEngine不是双端框架,不像ET那样直接限制前后端通信方式,
* JEngine告诉你该怎么搞,工具给你写完,后面的就要靠你自己了!
*
* 所以这里建议没接触过后端的,用nodeJS服务器,用里面的socketIO,当时我从没接触过后端到能撸双端游戏,这个东西功不可没
*
* 如果一定要写的,可以研究下JEvent,专门搞一个类处理事件,
* 里面的方法全写为void xxx(string event, JSONObject data),然后类打上[Subscriber]标签
* 然后写个JEvent来注册,在这里获取到event name 和event data 后直接JEvent.Post就能派发了,简单的很~
*/
}
/// <summary>
/// 这个用于连接其他web socket服务器,需要自己实现on方法,在OnMessageFromNormalServer方法内根据自己的消息模型自己实现。
/// 这个连接普通WebSocket服务器的方法监听,建议有服务器基础,且C#有经验的人去写监听,没经验的,也可以用这个做发送,但是监听这边会很麻烦
/// </summary>
public static void RunNormalServerDemo(string ip, int port)
{
/*
* 这个地方也有个配套demo,到时候会上传到GitHub,估计叫做JEngine.Net WebSokcet Server Demo
*/
//直接连接,使用默认配置(中间参数null),需要配置一个接收服务器消息的方法
JWebSocket socket = new JWebSocket($"ws://{ip}:{port}/demo", null, OnMessageFromNormalServer);
//带配置连接,需要配置一个接收服务器消息的方法
//JSocketConfig config = JSocketConfig.Default();
//config.debug = true;
//JSocket socket = new JSocket($"ws://{ip}:{port}/demo", config, OnMessageFromNormalServer);
socket.OnConnect((e) =>
{
Log.Print("服务端连接成功");
//发送hi到服务端
socket.SendToServer("hi");//同步
});
socket.OnError(e =>
{
Log.PrintError(e);
});
socket.OnDisconnect((e) =>
{
Log.Print("服务端连接关闭");
});
//此方法不阻塞
socket.Connect();
//断线重连事件
socket.OnReconnect(() =>
{
Log.Print("断开连接后重连成功");
});
//这个地方不能用SocketIO_On来监听事件,因为不同的人的消息模型不同,所以需要在OnMessageFromNormalServer内根据服务器发来的东西自己实现
}
/// <summary>
/// 这个用于连接socket-io服务器
/// </summary>
public static void RunSocketIOServerDemo(string ip, int port)
{
/* 使用前需要建立node js 服务器,并npm按照socket io,参考socketio的官网
* 将下面的js代码丢你nodejs服务器里并node运行
let server = require('socket.io');//socket
let io = new server(8001);//创建服务器于7999端口
console.log('服务器已开始运行');
//开始运行服务器
io.on('connection', async function(socket) {
//连接信息
console.log("有连接了,sid: "+socket.id);
//监听事件
socket.on('hi',function(){
//发送事件
socket.emit("hi_back");
console.log("已发送hi_back");
});
//发送事件+数据
var player = new Object();
player.id = 666;
player.name = "傑";
socket.emit("simulate_auth",player);
});
*/
//直接连接,使用默认配置
JWebSocket socket = new JWebSocket($"ws://{ip}:{port}/socket.io/?EIO=3&transport=websocket");
//带配置连接
//JSocketConfig config = JSocketConfig.Default();
//config.debug = true;
//JSocket socket = new JSocket($"ws://{ip}:{port}/socket.io/?EIO=3&transport=websocket", config);
socket.OnConnect(async (e) =>
{
Log.Print("服务端连接成功");
//发送hi到服务端
socket.EmitToSocketIOServer("hi");//同步
socket.EmitToSocketIOServerAsync("hi", (bool res) =>
{
Log.Print("异步并行发送" + (res ? "成功" : "失败"));
});//异步并行
var result = await socket.EmitToSocketIOServerAsync("hi");
Log.Print("纯异步发送" + (result ? "成功" : "失败"));//纯异步
});
socket.OnDisconnect((e) =>
{
Log.Print("服务端连接关闭");
});
//此方法不阻塞
socket.Connect();
//断线重连事件
socket.OnReconnect(() =>
{
Log.Print("断开连接后重连成功");
});
//监听hi_back事件
socket.SocketIO_On("hi_back", (e) =>
{
Log.Print("这里只会收到hi_back这个字符串,作为SocketIOEvent.Name,而这个事件的data为空");
Log.Print($"{e.name}: {e.data}");
Log.Print($"当前在线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");
});
//监听simulate_auth事件
socket.SocketIO_On("simulate_auth", (e) =>
{
Log.Print("这里SocketIOEvent.Name是simulate_auth,而这个事件的data是js服务器发来的json数据");
Log.Print($"{e.name}: {e.data.ToString()}");
Log.Print("解析JSONData也很简单");
var jsonData = e.data;
Log.Print($"服务端发来的数据的json的keys是:{string.Join(",", jsonData.keys)}");
Log.Print($"服务端发来的数据的id是:{jsonData["id"]}");
Log.Print($"服务端发来的数据的name是:{jsonData["name"]}");
Log.Print($"当前在线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");
});
}
}
}