本文是简述了Websocket的服务端和客户端的实时通讯过程,Websocket的服务端和客户端的具体使用使用了2种Websocket的服务端和2种客户端。
以下代码使用的是Visual Studio 2019 Enterprise版本,控制台项目使用的是 .NETFramework,Version=v4.7.2,同时为了调试方便,做了log4net日志处理,log4net日志的使用可以百度
Websocket服务端
1、新建项目ConsoleWebsocketServer
2、项目右键 管理Nuget程序包,,搜索 SuperWebSocketNETServer,添加即可
3、新建文件夹ServerEntities,然后再该文件夹下添加HttpAndWebsocket和ConsoleAppWebsocketServer这两个类,代码如下
HttpAndWebsocket类
using System;
using System.Net;using System.Net.WebSockets;using System.Text;using System.Threading;using System.Threading.Tasks;namespace ConsoleWebsocketServer.ServerEntities
{ public class HttpAndWebsocket { public async void Start(string url) { string url1 = "http://+:80/"; int Port = 1234; HttpListener httpListener = new HttpListener(); httpListener.Prefixes.Add("http://+:" + Port + "/"); httpListener.Start(); while (true) { try { HttpListenerContext httpListenerContext = await httpListener.GetContextAsync(); try { if (httpListenerContext.Request.IsWebSocketRequest) { ProcessRequest(httpListenerContext); } } catch (Exception) { httpListenerContext.Response.StatusCode = 400; httpListenerContext.Response.Close(); } } catch (Exception) { throw; } } }private async void ProcessRequest(HttpListenerContext listenerContext)
{ HttpListenerWebSocketContext httpListenerWebSocket;try
{ httpListenerWebSocket = await listenerContext.AcceptWebSocketAsync(null); } catch (Exception) { listenerContext.Response.StatusCode = 500; listenerContext.Response.Close(); return; } WebSocket webSocket = httpListenerWebSocket.WebSocket; try {while (webSocket.State == WebSocketState.Open)
{ byte[] returnBytes = new byte[10240]; WebSocketReceiveResult webSocketReceiveResult = await webSocket.ReceiveAsync(new ArraySegment<byte>(returnBytes), CancellationToken.None); string ReceivesData = Encoding.UTF8.GetString(returnBytes, 0, webSocketReceiveResult.Count); ReceivesData = $"我已经收到数据:{ReceivesData}"; returnBytes = Encoding.UTF8.GetBytes(ReceivesData); await webSocket.SendAsync(new ArraySegment<byte>(returnBytes), WebSocketMessageType.Text, true, CancellationToken.None); await Task.Delay(TimeSpan.FromSeconds(3)); } } catch (Exception) {throw;
} finally { if (webSocket != null) { webSocket.Dispose(); } } } }}
ConsoleAppWebsocketServer类
using SuperWebSocket;
using System;using System.Web;namespace ConsoleWebsocketServer.ServerEntities
{ /// <summary> /// SuperWebSocket服务端 /// </summary> public class ConsoleAppWebsocketServer { public static WebSocketServer ws = null;public void Start()
{ ws = new WebSocketServer(); ws.NewSessionConnected += Ws_NewSessionConnected; ws.NewMessageReceived += Ws_NewMessageReceived; ws.SessionClosed += Ws_SessionClosed; if (!ws.Setup("127.0.0.1", 1234)) { Console.WriteLine("ChatWebSocket 设置WebSocket服务侦听地址失败"); return; }if (!ws.Start())
{ Console.WriteLine("ChatWebSocket 启动WebSocket服务侦听失败"); return; } while (true) {}
}public void Ws_NewSessionConnected(WebSocketSession session)
{ Console.WriteLine("{0:HH:MM:ss} 与客户端:{1}创建新会话", DateTime.Now, GetSessionName(session)); var msg = string.Format("{0:HH:MM:ss} {1} 进入聊天室", DateTime.Now, GetSessionName(session));SendToAll(session, msg);
}private void Ws_NewMessageReceived(WebSocketSession session, string value)
{ var msg = string.Format("{0:HH:MM:ss} {1} 说: {2}", DateTime.Now, GetSessionName(session), value); Console.WriteLine($"{msg}"); SendToAll(session, msg); }public void Ws_SessionClosed(WebSocketSession session, SuperSocket.SocketBase.CloseReason value)
{ Console.WriteLine("{0:HH:MM:ss} 与客户端:{1}的会话被关闭 原因:{2}", DateTime.Now, GetSessionName(session), value); var msg = string.Format("{0:HH:MM:ss} {1} 离开聊天室", DateTime.Now, GetSessionName(session)); SendToAll(session, msg); }/// <summary>
/// 启动服务 /// </summary> /// <returns></returns> public void StartWebsocket() { if (!ws.Setup("127.0.0.1", 1234)) { Console.WriteLine("ChatWebSocket 设置WebSocket服务侦听地址失败"); return; }if (!ws.Start())
{ Console.WriteLine("ChatWebSocket 启动WebSocket服务侦听失败"); return; }Console.WriteLine("ChatWebSocket 启动服务成功");
}/// <summary>
/// 停止侦听服务 /// </summary> public void Stop() {if (ws != null)
{ ws.Stop(); } }public string GetSessionName(WebSocketSession session)
{ return HttpUtility.UrlDecode(session.Path.TrimStart('/')); }public void SendToAll(WebSocketSession session, string msg)
{ foreach (var sendSession in session.AppServer.GetAllSessions()) { sendSession.Send(msg); } } }}
4、ConsoleWebsocketServer的Program.cs 代码如下
using ConsoleWebsocketServer.ServerEntities;
using SuperWebSocket;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Web;namespace ConsoleWebsocketServer
{ class Program { public static WebSocketServer ws = null; static void Main(string[] args) { #region 启动http服务接受websocket请求 Console.WriteLine("启动http服务的WebSocket服务"); HttpAndWebsocket httpAndWebsocket = new HttpAndWebsocket(); httpAndWebsocket.Start("ws://127.0.0.1:1234"); Console.WriteLine("ChatWebSocket 启动服务成功"); Console.WriteLine("按 Enter 退出..."); Console.ReadKey(); #endregion#region 启动websocket服务接受websocket请求
//Console.WriteLine("WebSocket服务"); //ws = new WebSocketServer(); //ws.NewSessionConnected += Ws_NewSessionConnected; //ws.NewMessageReceived += Ws_NewMessageReceived; //ws.SessionClosed += Ws_SessionClosed; //if (!ws.Setup("127.0.0.1", 1234)) //{ // Console.WriteLine("ChatWebSocket 设置WebSocket服务侦听地址失败"); // return; //}//if (!ws.Start())
//{ // Console.WriteLine("ChatWebSocket 启动WebSocket服务侦听失败"); // return; //}//Console.WriteLine("ChatWebSocket 启动服务成功");
//Console.WriteLine("按 Enter 推出..."); //Console.ReadKey(); //ws.Stop(); #endregion }public static void Ws_NewSessionConnected(WebSocketSession session)
{ Console.WriteLine("{0:HH:MM:ss} 与客户端:{1}创建新会话", DateTime.Now, GetSessionName(session)); var msg = string.Format("{0:HH:MM:ss} {1} 进入聊天室", DateTime.Now, GetSessionName(session));SendToAll(session, msg);
}private static void Ws_NewMessageReceived(WebSocketSession session, string value)
{ var msg = string.Format("{0:HH:MM:ss} {1} 说: {2}", DateTime.Now, GetSessionName(session), value); Console.WriteLine($"{msg}"); SendToAll(session, msg); }public static void Ws_SessionClosed(WebSocketSession session, SuperSocket.SocketBase.CloseReason value)
{ Console.WriteLine("{0:HH:MM:ss} 与客户端:{1}的会话被关闭 原因:{2}", DateTime.Now, GetSessionName(session), value); var msg = string.Format("{0:HH:MM:ss} {1} 离开聊天室", DateTime.Now, GetSessionName(session)); SendToAll(session, msg); }/// <summary>
/// 启动服务 /// </summary> /// <returns></returns> public static void Start() { if (!ws.Setup("127.0.0.1", 1234)) { Console.WriteLine("ChatWebSocket 设置WebSocket服务侦听地址失败"); return; }if (!ws.Start())
{ Console.WriteLine("ChatWebSocket 启动WebSocket服务侦听失败"); return; }Console.WriteLine("ChatWebSocket 启动服务成功");
}
/// <summary>
/// 停止侦听服务 /// </summary> public static void Stop() {if (ws != null)
{ ws.Stop(); } }public static string GetSessionName(WebSocketSession session)
{ return HttpUtility.UrlDecode(session.Path.TrimStart('/')); }public static void SendToAll(WebSocketSession session, string msg)
{ foreach (var sendSession in session.AppServer.GetAllSessions()) { sendSession.Send(msg); } } }}
Websocket客户端
1、新建项目ConsoleWebsocketClient
2、项目右键 管理Nuget程序包,,搜索 log4net,WebSocket4NET,添加即可
3、新建文件夹ClientEntities,然后再该文件夹下添加ClientWebsocketEntity和ConsoleAppWebsocketClient这两个类,代码如下
ClientWebsocketEntity类
using ConsoleWebsocketClient.CommonUntils;
using System;using System.IO;using System.Net.WebSockets;using System.Text;using System.Threading;using System.Threading.Tasks;namespace ConsoleWebsocketClient.ClientEntities
{ /// <summary> /// ClientWebsocket客户端实体类 /// </summary> public class ClientWebsocketEntity { #region Fields And Propertities/// <summary>
/// ClientWebsocket客户端Url /// </summary> public string SocketUrl { get; set; } = "ws://127.0.0.1:1234/"; //public string SocketUrl { get; set; } = "ws://192.168.1.198:1234/";/// <summary>
/// ClientWebsocket客户端对象 /// </summary> public ClientWebSocket ClientWebSocket { get; set; }/// <summary>
/// 消息回传的委托定义 /// </summary> /// <param name="retValue"></param> public delegate void ShowMessage(string retValue);/// <summary>
/// 消息回传 /// </summary> public ShowMessage ReturnMessage;#endregion
#region Methods
/// <summary> /// 构造函数初始化 /// </summary> public ClientWebsocketEntity() { ClientWebSocket = new ClientWebSocket(); //ClientWebsocketConnect(); }public void StartClient()
{ ClientWebsocketConnect(); }/// <summary>
/// ClientWebsocket客户端连接Websocket服务端 /// </summary> public async void ClientWebsocketConnect() { try { await ClientWebSocket.ConnectAsync(new Uri(SocketUrl), CancellationToken.None); ClientWebsocketSendMessage(); ClientWebsocketReceivedMessage(); } catch (Exception) {throw;
} }/// <summary>
/// ClientWebsocket客户端向Websocket服务端发送消息 /// </summary> public async void ClientWebsocketSendMessage() { try { while (true) { byte[] bytess = Encoding.Default.GetBytes($"login#22222"); await ClientWebSocket.SendAsync(new ArraySegment<byte>(bytess), WebSocketMessageType.Text, true, new CancellationToken()); await Task.Delay(1000 * 3); } //while (ClientWebSocket.State == WebSocketState.Open) //{ // byte[] buffer = new byte[10240]; // await ClientWebSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None); // await Task.Delay(TimeSpan.FromSeconds(3)); //} } catch (Exception ex) { LogHelper.Instance.Error($"{ex.Message}"); throw; } }/// <summary>
/// ClientWebsocket客户端从Websocket服务端接收消息 /// </summary> public async void ClientWebsocketReceivedMessage() { try { //while (true) //{ // //byte[] bytess = Encoding.Default.GetBytes($"TestWebsocket发送数据 {s} "); // //cln.SendAsync(new ArraySegment<byte>(bytess), WebSocketMessageType.Text, true, new CancellationToken()).Wait(); // //s++; // string returnValue = await GetAsyncValue(ClientWebSocket);//异步方法 // ReturnMessage?.Invoke(returnValue); //}while (ClientWebSocket.State == WebSocketState.Open)
{ ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[1024 * 4]); WebSocketReceiveResult result = await ClientWebSocket.ReceiveAsync(buffer, CancellationToken.None); if (result.EndOfMessage) { if (result.MessageType == WebSocketMessageType.Text) { //string retValue = Encoding.UTF8.GetString(buffer.Array).Replace("\0", "").Trim(); // Encoding.UTF8.GetString(buffer.Array)会多出很多空余的字符,添加Replace("\0", "").Trim()处理掉就可以了 string retValue = Encoding.UTF8.GetString(buffer.Array, 0, result.Count); ReturnMessage?.Invoke(retValue); } } }//WebSocketReceiveResult result;
//ArraySegment<byte> buffer; //string retValue; //while (ClientWebSocket.State == WebSocketState.Open) //{ // using (var ms = new MemoryStream()) // { // buffer = new ArraySegment<byte>(new byte[1024]); // do // { // result = await ClientWebSocket.ReceiveAsync(buffer, CancellationToken.None); // ms.Write(buffer.Array, buffer.Offset, result.Count); // } // while (!result.EndOfMessage); // ms.Seek(0, SeekOrigin.Begin); // if (result.MessageType == WebSocketMessageType.Text) // { // using (var reader = new StreamReader(ms, Encoding.UTF8)) // { // retValue = reader.ReadToEnd(); // ReturnMessage?.Invoke(retValue); // } // } // } //}}
catch (Exception ex) when (!string.IsNullOrEmpty(ex.Message)) { LogHelper.Instance.Error($"{ex.Message}"); throw; } }public static async Task<string> GetAsyncValue(ClientWebSocket clientWebSocket)
{ string returnValue = null; ArraySegment<Byte> buffer = new ArraySegment<byte>(new Byte[8192]); WebSocketReceiveResult result = null; using (var ms = new MemoryStream()) { do { result = await clientWebSocket.ReceiveAsync(buffer, CancellationToken.None); ms.Write(buffer.Array, buffer.Offset, result.Count); } while (!result.EndOfMessage); ms.Seek(0, SeekOrigin.Begin); if (result.MessageType == WebSocketMessageType.Text) { using (var reader = new StreamReader(ms, Encoding.UTF8)) { returnValue = reader.ReadToEnd(); //Console.WriteLine(returnValue); } } } return returnValue; } #endregion }}
ConsoleAppWebsocketClient类
using System;
using System.Collections.Generic;using System.Text;using System.Threading;namespace ConsoleWebsocketClient.ClientEntities
{ class ConsoleAppWebsocketClient { static WebSocket4Net.WebSocket webSocket4NetFaceValidate = null; static void Start(string[] args) { Console.WriteLine("WebSocket客户端"); Thread.Sleep(TimeSpan.FromSeconds(8)); webSocket4NetFaceValidate = new WebSocket4Net.WebSocket("ws://127.0.0.1:1234"); webSocket4NetFaceValidate.Opened += WebSocket4NetFaceValidate_Opened; webSocket4NetFaceValidate.MessageReceived += WebSocket4NetFaceValidate_MessageReceived; webSocket4NetFaceValidate.Error += WebSocket4NetFaceValidate_Error; webSocket4NetFaceValidate.Open(); //WebSocketSendmessage(); //Thread thread = new Thread(WebSocketSendmessage); //thread.IsBackground = true; //thread.Start(); Console.ReadKey(); }private static void WebSocket4NetFaceValidate_Error(object sender, SuperSocket.ClientEngine.ErrorEventArgs e)
{ throw new NotImplementedException(); }public static void WebSocketSendmessage()
{ int s = 88; while (true) { webSocket4NetFaceValidate.Send(s.ToString()); s++; System.Threading.Thread.Sleep(TimeSpan.FromSeconds(3));}
Console.WriteLine($"begin#123456"); byte[] bytess = Encoding.Default.GetBytes($"begin#123456"); IList<ArraySegment<byte>> list = new List<ArraySegment<byte>>(); list.Add(new ArraySegment<byte>(bytess)); webSocket4NetFaceValidate.Send(list); }private static void WebSocket4NetFaceValidate_Opened(object sender, EventArgs e)
{ Console.WriteLine($"begin#123456"); byte[] bytess = Encoding.Default.GetBytes($"begin#123456"); IList<ArraySegment<byte>> list = new List<ArraySegment<byte>>(); list.Add(new ArraySegment<byte>(bytess)); webSocket4NetFaceValidate.Send(list); }private static void WebSocket4NetFaceValidate_MessageReceived(object sender, WebSocket4Net.MessageReceivedEventArgs e)
{ try { string returnMessage = e.Message; if (string.IsNullOrEmpty(returnMessage)) { return; } Console.WriteLine(returnMessage); } catch (Exception ex) {}
finally {}
} }}
4、ConsoleWebsocketClient的Program.cs 代码如下
using ConsoleWebsocketClient.ClientEntities;
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;using System.Threading.Tasks;namespace ConsoleWebsocketClient
{ class Program { static WebSocket4Net.WebSocket webSocket4Net = null; static void Main(string[] args) { #region ClientWebsocke客户端 //Thread.Sleep(TimeSpan.FromSeconds(3)); Console.WriteLine("WebSocket客户端"); for (int i = 0; i < 1; i++) { //System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5)); //System.Threading.Tasks.Task.Factory.StartNew(BBB, i); //Task.Delay(2000);ClientWebsocketEntity clientWebsocketEntity = new ClientWebsocketEntity();
clientWebsocketEntity.ReturnMessage = Addlog; clientWebsocketEntity.StartClient(); } Console.ReadKey(); #endregion#region WebSocket4Net客户端
//Console.WriteLine("WebSocket客户端"); //webSocket4Net = new WebSocket4Net.WebSocket("ws://127.0.0.1:1234"); //webSocket4Net.Opened += WebSocket4Net_Opened; //webSocket4Net.MessageReceived += WebSocket4Net_MessageReceived; //webSocket4Net.Error += WebSocket4Net_Error; //webSocket4Net.Open(); WebSocketSendmessage(); //Thread thread = new Thread(WebSocketSendmessage); //thread.IsBackground = true; //thread.Start(); //Console.ReadKey(); #endregion }public static void Addlog(string sss)
{ Console.WriteLine(sss); }public static void WebSocketSendmessage()
{ int s = 88; while (true) { webSocket4Net.Send(s.ToString()); s++; Thread.Sleep(TimeSpan.FromSeconds(3));}
}private static void WebSocket4Net_Error(object sender, SuperSocket.ClientEngine.ErrorEventArgs e)
{ //throw new NotImplementedException(); }private static void WebSocket4Net_Opened(object sender, EventArgs e)
{ Console.WriteLine($"begin#123456"); byte[] bytess = Encoding.Default.GetBytes($"begin#123456"); IList<ArraySegment<byte>> list = new List<ArraySegment<byte>>(); list.Add(new ArraySegment<byte>(bytess)); webSocket4Net.Send(list); }private static void WebSocket4Net_MessageReceived(object sender, WebSocket4Net.MessageReceivedEventArgs e)
{ try { string returnMessage = e.Message; if (string.IsNullOrEmpty(returnMessage)) { return; } Console.WriteLine(returnMessage); } catch (Exception ex) {}
finally {}
} }}
5、ConsoleWebsocketClient的App.config 代码如下
<?xml version="1.0" encoding="utf-8" ?>
<configuration> <configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"/> </configSections> <log4net> <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender"> <param name="File" value="Log\Log.txt" /> <param name="AppendToFile" value="true" /> <param name="MaxSizeRollBackups" value="100" /> <param name="MaximumFileSize" value="2MB" /> <param name="RollingStyle" value="Size" /> <param name="StaticLogFileName" value="true" /> <layout type="log4net.Layout.PatternLayout"> <param name="ConversionPattern" value="%-15p %d [%c] %m %n" /> </layout> </appender> <root> <level value="all" /> <appender-ref ref="RollingLogFileAppender" /> </root> </log4net> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" /> </startup></configuration>
5、为了测试方便添加了HTML文件websockettest.html
<!DOCTYPE HTML>
<html> <head> <meta http-equiv="content-type" content="text/html" /> <meta name="author" content="https://www.baidu.com" /> <title>websocket test</title> <script> var socket; function Connect(){ try{ socket=new WebSocket('ws://127.0.0.1:1234'); }catch(e){ alert('error'); return; } socket.onopen = sOpen; socket.onerror = sError; socket.onmessage= sMessage; socket.onclose= sClose; } function sOpen(){ alert('connect success!'); } function sError(e){ alert("error " + e); } function sMessage(msg){ document.getElementById("msgrecv").value = msg.data; } function sClose(e){ alert("connect closed:" + e.code); } function Send(){ socket.send(document.getElementById("msg").value); } function Close(){ socket.close(); } </script></head> <body> <input id="msg" type="text" size = "200" > <input id="msgrecv" type="text" size = "200"> <button id="connect" οnclick="Connect();">Connect</button> <button id="send" οnclick="Send();">Send</button> <button id="close" οnclick="Close();">Close</button></body>
</html>
以上ConsoleWebsocketServer项目和ConsoleWebsocketClient项目都建好了,就可以运行了,其中可以设置两种Websocket服务端和Websocket客户端(websockettest.html网页端,也是客户端)
服务端
客户端
运行结果