Home > Article > Backend Development > Detailed explanation of examples of implementing WebSocket server-side instant messaging using .NET
This article mainly introduces .NET to implement instant messaging and WebSocket server examples. The editor thinks it is quite good, so I will share it with you now and give it as a reference. Let’s follow the editor and take a look.
Common methods of instant messaging
1. There are many third-party platforms such as Google and Tencent Huanxin, among which Google Instant Messenger is free, but free means free and not easy to use. Some other third parties generally charge a fee, and the usage requirements limit the flow (1s/limit x messages) or limit the number of users.
But the stability is not bad, and it can relieve the service pressure
2.System.Net.Sockets.Socket, and can also write a better server. It was used more before .NET 4.5 and was cumbersome to use. It is necessary to parse the data packets and other operations (but it seems that there are methods for processing ultra-long packets on the Internet)
3.System.Net.WebSockets.WebSocket, this is something that came out of .NET 4.5, and is very useful for the server environment There are also requirements, IIS8 and above. This means that the IIS that comes with Windows Server2008R2 does not support it, but the IIS that comes with Windows 8 and Server2012 or above does. This article mainly describes examples of this method
Complete process
1). The client request connection
code is as follows:
ws = new WebSocket('ws://' + window.location.hostname + ':' + window.location.port + '/Handler1.ashx?user=' + $("#user" ).val());
2). The server obtains the connection object and stores it in the connection pool
CONNECT_POOL.Add(user, socket);
3). The connection object starts listening (Each client and server save long links)
The code is as follows:
WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
4). Client A sends a message to B
ws.send($("#to").val() + "|" + $('#content').val());
5). Server A’s connection object listens to the message from A
string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);
6). Parse the message body (B|Hello Me Is A) Get the receiver ID, find B's server connection object in the connection pool according to the receiver ID, and push the message to B client through B's connection object
WebSocket destSocket = CONNECT_POOL[descUser]; await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
7). Server A The connection object continues to listen
The code is as follows:
WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
8).Client B receives the pushed message
ws.onmessage = function (evt) { $('#msg').append('<p>' + evt.data + '</p>'); }
The following is the complete code
Client part
The client is extremely simple. Under normal circumstances, it uses WebSocket directly, and then listens to several events of WebSocket and it is ok. When connecting, you can pass in the ID of the current connector (user number), and when sending a message, use the method "receiver ID|I am the message content", such as "A|Hello A, I am B!"
But there are still some common scenarios that need to be dealt with when using mobile terminals
1: Turn off the screen of the mobile phone, and when IOS turns off the screen, WebSocket will immediately lose the connection, AndroidIt will wait for a while before losing the connection. The server can detect the loss of connection
2: The network is unstable and WebSocket will not lose the connection immediately if the network is disconnected, and the server cannot know it. (You can design a heartbeat mechanism on the server side to regularly send messages to users in the connection pool to detect whether users maintain connections)
3: Others, etc... (Sudden shutdown, end of application in the background)
No matter which one, the client can first determine the status of ws when sending a message (or the network connection is restored, or the screen is turned on). If it is not in the connection status, it needs to reconnect (just download new)
<script> var ws; $().ready(function () { $('#conn').click(function () { ws = new WebSocket('ws://' + window.location.hostname + ':' + window.location.port + '/Handler1.ashx?user=' + $("#user").val()); $('#msg').append('<p>正在连接</p>'); ws.onopen = function () { $('#msg').append('<p>已经连接</p>'); } ws.onmessage = function (evt) { $('#msg').append('<p>' + evt.data + '</p>'); } ws.onerror = function (evt) { $('#msg').append('<p>' + JSON.stringify(evt) + '</p>'); } ws.onclose = function () { $('#msg').append('<p>已经关闭</p>'); } }); $('#close').click(function () { ws.close(); }); $('#send').click(function () { if (ws.readyState == WebSocket.OPEN) { ws.send($("#to").val() + "|" + $(&#39;#content&#39;).val()); } else { $('#tips').text('连接已经关闭'); } }); }); </script>
目的用户
Server-side part
The server-side uses Handler (WebAPI can also be used), mainly using the WebSocket class. There are relatively detailed comments in the code. Here are just some issues that need attention
1: Dictionary06f0454b88eb565f354426b6933e3e6e CONNECT_POOL: User connection pool. When requesting the Handler, the user ID of the current connector will be passed in. The server maintains all connected user IDs and the current user's WebSocket connection object 2: Dictionary4cbd2b4693e407669a7a5cf742c2749d> MESSAGE_POOL: Offline message pool. If A->B sends a message, and B is currently not online for some reason (sudden network disconnection/black screen, etc.), the message will be saved first (2 days), and B's offline message will be saved immediately after B is connected. Push it to him. (2: MessageInfo: Offline Entity. Record the time and content of the current offline message)using System; using System.Collections; 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 WebApplication1 { /// <summary> /// 离线消息 /// </summary> public class MessageInfo { public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent) { MsgTime = _MsgTime; MsgContent = _MsgContent; } public DateTime MsgTime { get; set; } public ArraySegment<byte> MsgContent { get; set; } } /// <summary> /// Handler1 的摘要说明 /// </summary> public class Handler1 : IHttpHandler { private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池 private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池 public void ProcessRequest(HttpContext context) { if (context.IsWebSocketRequest) { context.AcceptWebSocketRequest(ProcessChat); } } private async Task ProcessChat(AspNetWebSocketContext context) { WebSocket socket = context.WebSocket; string user = context.QueryString["user"].ToString(); try { #region 用户添加连接池 //第一次open时,添加到连接池中 if (!CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Add(user, socket);//不存在,添加 else if (socket != CONNECT_POOL[user])//当前对象不一致,更新 CONNECT_POOL[user] = socket; #endregion #region 离线消息处理 if (MESSAGE_POOL.ContainsKey(user)) { List<MessageInfo> msgs = MESSAGE_POOL[user]; foreach (MessageInfo item in msgs) { await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None); } MESSAGE_POOL.Remove(user);//移除离线消息 } #endregion string descUser = string.Empty;//目的用户 while (true) { if (socket.State == WebSocketState.Open) { ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]); WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None); #region 消息处理(字符截取、消息转发) try { #region 关闭Socket处理,删除连接池 if (socket.State != WebSocketState.Open)//连接关闭 { if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池 break; } #endregion string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息 string[] msgList = userMsg.Split('|'); if (msgList.Length == 2) { if (msgList[0].Trim().Length > 0) descUser = msgList[0].Trim();//记录消息目的用户 buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1])); } else buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg)); if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线 { WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端 if (destSocket != null && destSocket.State == WebSocketState.Open) await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None); } else { Task.Run(() => { if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中 MESSAGE_POOL.Add(descUser, new List<MessageInfo>()); MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息 }); } } catch (Exception exs) { //消息转发异常处理,本次消息忽略 继续监听接下来的消息 } #endregion } else { break; } }//while end } catch (Exception ex) { //整体异常处理 if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user); } } public bool IsReusable { get { return false; } } } }
The above is the detailed content of Detailed explanation of examples of implementing WebSocket server-side instant messaging using .NET. For more information, please follow other related articles on the PHP Chinese website!