/// <summary> /// 保存历史消息 /// </summary> /// <param name="data"></param> public static void SaveHistoricalMessg(ChatData data) { var size = 40; lock (lockSaveMsg) { historicalMessg.Add(data); } if (historicalMessg.Count >= size) { lock (lockSaveMsg) { historicalMessg.RemoveRange(0, 30); } } }
/// <summary> /// 发送消息到所有人 /// </summary> /// <param name="sockets"></param> /// <param name="data"></param> /// <returns></returns> public static async Task 发送消息到所有人(List <WebSocket> sockets, ChatData data) { 保存历史消息(data);//保存历史消息 var chatData = JsonConvert.SerializeObject(data); var buffer = Encoding.UTF8.GetBytes(chatData); var arraySegment = new ArraySegment <byte>(buffer); //循环发送消息 foreach (var tempsocket in sockets) { if (tempsocket.State == WebSocketState.Open) { //发送消息 await tempsocket.SendAsync(arraySegment, WebSocketMessageType.Text, true, CancellationToken.None); } } }
/// <summary> /// 发送消息到所有人 /// </summary> /// <param name="sockets"></param> /// <param name="arraySegment"></param> /// <returns></returns> public async static Task SendToWebSocketsAsync(List <WebSocket> sockets, ChatData data) { SaveHistoricalMessg(data);//保存历史消息 var chatData = JsonConvert.SerializeObject(data); var buffer = Encoding.UTF8.GetBytes(chatData); ArraySegment <byte> arraySegment = new ArraySegment <byte>(buffer); //循环发送消息 for (int i = 0; i < sockets.Count; i++) { var tempsocket = sockets[i]; if (tempsocket.State == WebSocketState.Open) { //发送消息 await tempsocket.SendAsync(arraySegment, WebSocketMessageType.Text, true, CancellationToken.None); } } }
/// <summary> /// 保存历史消息 /// </summary> /// <param name="data"></param> public static void 保存历史消息(ChatData data) { const int size = 40; lock (lockSaveMsg) { 历史消息列表.Add(data); } lock (lockSaveMsg) { if (历史消息列表.Count < size) { return; } lock (lockSaveMsg) { 历史消息列表.RemoveRange(0, 30); } } }
/// <summary> /// 接收请求 /// </summary> /// <param name="httpContext"></param> /// <param name="n"></param> /// <returns></returns> private static async Task 接收请求(HttpContext httpContext, Func <Task> n) { if (!httpContext.WebSockets.IsWebSocketRequest) { return; } //建立一个WebSocket连接请求 var socket = await httpContext.WebSockets.AcceptWebSocketAsync(); //判断最大连接数 if (_sockets.Count >= 100) { await socket.CloseAsync(WebSocketCloseStatus.PolicyViolation, "连接超过最大限制,请稍候加入群聊 ...", CancellationToken.None); return; } lock (objLock) { _sockets.Add(socket);//加入群聊 } var buffer = new byte[BufferSize]; //根据请求头获取 用户名 var userName = httpContext.Request.Query["userName"].ToString(); var chatData = new ChatData { info = userName + " 进入房间。当前在线人" + _sockets.Count + "人~~" }; //群发上线通知 await 发送消息到所有人(_sockets, chatData); while (true) { try { //建立连接,阻塞等待接收消息 var incoming = await socket.ReceiveAsync(new ArraySegment <byte>(buffer), CancellationToken.None); //如果主动退出,则移除 if (incoming.MessageType == WebSocketMessageType.Close)//incoming.CloseStatus == WebSocketCloseStatus.EndpointUnavailable WebSocketCloseStatus.NormalClosure) { lock (objLock) { _sockets.Remove(socket);//移除 } chatData = new ChatData { info = userName + " 离开房间。还剩" + _sockets.Count + "人~~" }; await 发送消息到所有人(_sockets, chatData); break; //【注意】::这里一定要记得 跳出循环 (坑了好久) } //转字符串,然后序列化,然后赋值,然后再序列化 var chatDataStr = await 转字符串(new ArraySegment <byte>(buffer, 0, incoming.Count)); if (chatDataStr == "heartbeat")//如果是心跳检查,则直接跳过 { continue; } chatData = JsonConvert.DeserializeObject <ChatData>(chatDataStr); chatData.time = DateTime.Now;//使用服务器时间 await 发送消息到所有人(_sockets.Where(t => t != socket).ToList(), chatData); } catch (Exception ex) //因为 nginx 没有数据传输 会自动断开 然后就会异常。 { 日志记录(ex.Message); _sockets.Remove(socket);//移除 chatData = new ChatData { info = userName + " 离开房间。还剩" + _sockets.Count + "人~~" }; await 发送消息到所有人(_sockets, chatData); //【注意】::这里很重要 (如果不发送关闭会一直循环,且不能直接break。) await socket.CloseAsync(WebSocketCloseStatus.PolicyViolation, "未知异常 ...", CancellationToken.None); // 后面 就不走了? CloseAsync也不能 try 包起来? } } }