1,nuget引入包Fleck,支持framework、core,相同代码
2,直接上代码
public static class WebSocketConfig
{
//客户端url以及其对应的Socket对象字典
public static Dictionary<string, IWebSocketConnection> dic_Sockets = new Dictionary<string, IWebSocketConnection>();
private static List<string> urList = new List<string>();
private static System.Timers.Timer timersHeartbeat = new System.Timers.Timer();
private static object lockObj = new object();
/// <summary>
/// 收到设备通信信息,触发是事件
/// </summary>
public static event Action<JObject, IWebSocketConnection> ReceiveMessageEvent;
public static string HostName
{
get { return System.Net.Dns.GetHostName().Trim(); }
}
private static WebSocketServer server;
public static async Task OpenSocketConfig()
{
await Task.Factory.StartNew(() =>
{
#region 启动websocket
//创建
server = new WebSocketServer("wss://0.0.0.0:443");//监听所有的的地址,无安全证书,则wss改为ws,下行代码(加载证书)可注释
server.Certificate = new X509Certificate2("ca.pfx");
//出错后进行重启
server.RestartAfterListenError = true;
//开始监听
server.Start(socket =>
{
socket.OnOpen = () => //连接建立事件
{
ThreadPool.QueueUserWorkItem(q =>
{
//获取客户端的url
string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort;
lock (lockObj)
{
dic_Sockets.Add(clientUrl, socket);
}
});
};
socket.OnClose = () => //连接关闭事件
{
string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort;
//如果存在这个客户端,那么对这个socket进行移除
if (dic_Sockets.ContainsKey(clientUrl))
{
//注:Fleck中有释放
//关闭对象连接
//if (dic_Sockets[clientUrl] != null)
//{
//dic_Sockets[clientUrl].Close();
//}
lock (lockObj)
{
dic_Sockets.Remove(clientUrl);
}
}
};
socket.OnMessage = message => //接受客户端消息事件
{
string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort;
var id =socket.ConnectionInfo.Id;
ThreadPool.QueueUserWorkItem(qu =>
{
JObject loginObj = JObject.Parse(message);
#region 设备登录验证
if (loginObj.TryGetValue("cmd", out JToken loginValue) && "login".Equals(loginValue.ToString()))
{
JObject loginData = new JObject();
loginData.Add("cmd", "login_resp");
loginData.Add("ret", 200);
loginData.Add("msg", "login resp ok");
string logoCmd = JsonConvert.SerializeObject(loginData);
byte[] logoBytes = Encoding.UTF8.GetBytes(logoCmd);
socket.Send(logoCmd);
}
#endregion
//登录信息,设备心跳返回信息,不触发事件
if (loginObj.TryGetValue("cmd", out JToken msg) &&
!"login".Equals(msg.ToString()) &&
!"heartbeat_resp".Equals(msg.ToString()))
{
if (ReceiveMessageEvent != null)
{
ReceiveMessageEvent.Invoke(loginObj, socket);
}
}
});
};
socket.OnError = error => //连接发生异常
{
string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort;
lock (lockObj)
{
dic_Sockets.Remove(clientUrl);
}
};
});
//心跳-定时任务
timersHeartbeat.AutoReset = true;
timersHeartbeat.Enabled = true;
timersHeartbeat.Interval = 8000;
timersHeartbeat.Elapsed += Heartbeart;
timersHeartbeat.Start();
#endregion
});
}
public static void CloseSocekt()
{
if (server != null)
{
server.Dispose();
}
}
/// <summary>
/// 给设备发送心跳数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void Heartbeart(object sender, ElapsedEventArgs e)
{
JObject heardData = new JObject();
heardData.Add("cmd", "heartbeat");
heardData.Add("ret", 200);
heardData.Add("msg", "heartbeat resp ok");
string heardCmd = JsonConvert.SerializeObject(heardData);
timersHeartbeat.Stop();
try
{
lock (lockObj)
{
ICollection<IWebSocketConnection> wscList = dic_Sockets.Values;
foreach (var item in wscList)
{
if (item.IsAvailable)
{
item.Send(heardCmd);
}
}
}
}
catch (Exception exception)
{
}
timersHeartbeat.Start();
}
}