2.需求描述
原本是为了给做unity3d客户端开发的同事提供不定时的消息推送,比如商城购买道具后服务端将道具信息推送给客户端。
本篇文章简化理解,用“相关部门开展活动,向全市人民征集社会服务改善意见”为例子。但核心想法一致:单向推送。所以这个功能并不是聊天室,不需要客户端和客户端之间互相通信。核心界面只和服务端建立WebSocket连接,推送消息全部来自其他地方。
只有核心页面和服务端建立WebSocket连接,其他市民们都是通过web开发者耳熟能详的http协议在发送消息,不要以为是市民们和部门公告栏玩WebSocket互动。
3.代码如下,复制即可使用
①WebSocket帮助类,负责建立连接和推送消息
using System; using System.Collections.Generic; using System.Linq; using System.Net.WebSockets; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Web; using System.Web.WebSockets; namespace WSTest { public class WSHelper { /// <summary> /// 保存客户端的WebSocket对象 /// </summary> private static readonly Dictionary<string, WebSocket> dicSockets = new Dictionary<string, WebSocket>(); #region 构建线程安全的单例模式 private static WSHelper _instance; private WSHelper() { } public static WSHelper GetInstance() { if (_instance == null) { lock (dicSockets) { if (_instance == null) { _instance = new WSHelper(); } } } return _instance; } #endregion /// <summary> /// 和客户端建立WebSocket连接 /// </summary> /// <param>客户端发送的WebSocket相关信息</param> /// <returns></returns> public async Task ProcessWSChat(AspNetWebSocketContext arg) { // 1.获取请求的客户端WebSocket对象 WebSocket socket = arg.WebSocket; // 2.获取自定义的参数 string adminUserKey = arg.QueryString["adminUserKey"]; if (string.IsNullOrEmpty(adminUserKey)) return; // 3.将用户编号作为标识客户端唯一性的Key,保存客户端的WebSocket对象 dicSockets[adminUserKey] = socket; while (true) { ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[1024 * 10]); WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None); try { if (socket.State != WebSocketState.Open) { dicSockets.Remove(adminUserKey); break; } } catch { break; } } } /// <summary> /// 服务端向客户端推送消息 /// </summary> public bool SendMsg(string message, string adminUserKey) { WebSocket socket = null; if (dicSockets.ContainsKey(adminUserKey)) { socket = dicSockets[adminUserKey]; } else { return false; } //【重要】执行下面socket.State代码可能会抛异常"无法访问已经释放的对象", // 因为客户端已经处于断电、断网、强制关闭、刷新等状态,当前的WebSocket对象已经失去价值,直接删除即可 try { if (socket.State == WebSocketState.Open) { ArraySegment<byte> buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(message)); socket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None); return true; } } catch { dicSockets.Remove(adminUserKey); return false; } return false; } } }