赞
踩
c# superwebsocket服务端可以寄宿在控制台程序、窗体程序、Windows服务
c# websocket客户端可以是控制台程序、窗体程序、Windows服务、html、手机,能连上websocket的就行了
服务端可以开启wss安全链接
如果想做即时通讯,双工通讯,或者因为频繁发送http请求导致的web服务器承受不住,都可以转用websocket
websocket 有良好的交互体验,快速的数据传输
websocket 开发简单,部署方便,上手没难度
我这里展示了,把websocket服务端寄宿在Windows服务里,客户端则用控制台访问和用web访问,调试阶段,为了避免频繁停启Windows服务,所以我用控制台启动了服务端,生产环境就可以直接把exe执行文件注册成服务了
底部有源代码百度盘下载,Windows服务安装方法
1.服务端
把websocket服务端类,拷贝到项目里
using SuperSocket.SocketBase; using SuperSocket.SocketBase.Config; using SuperSocket.SocketEngine; using SuperWebSocket; using System; using System.Threading; using System.Threading.Tasks; //install-package SuperWebSocket //install-package nlog //install-package nlog.config namespace WebSocketService { public class WSocketServer:IDisposable { public static NLog.Logger _Logger = NLog.LogManager.GetCurrentClassLogger(); #region 向外传递数据事件 public event Action<WebSocketSession, string> MessageReceived; public event Action<WebSocketSession> NewConnected; public event Action<WebSocketSession> Closed; #endregion public WebSocketServer WebSocket; Thread _thread; bool _isRunning = true; public WSocketServer() { } #region WebSockertServer /// <summary> /// 开启服务端 /// </summary> /// <param name="port"></param> /// <param name="serverName"></param> /// <param name="isUseCertificate"></param> /// <param name="serverStoreName"></param> /// <param name="serverSecurity"></param> /// <param name="serverThumbprint"></param> /// <returns></returns> public bool Open(int port, string serverName, bool isUseCertificate = false, string serverStoreName = "", string serverSecurity = "", string serverThumbprint = "") { bool isSetuped = false; try { this.WebSocket = new WebSocketServer(); var serverConfig = new ServerConfig { Name = serverName, MaxConnectionNumber = 10000, //最大允许的客户端连接数目,默认为100。 Mode = SocketMode.Tcp, Port = port, //服务器监听的端口。 ClearIdleSession = false, //true或者false, 是否清除空闲会话,默认为false。 ClearIdleSessionInterval = 120,//清除空闲会话的时间间隔,默认为120,单位为秒。 ListenBacklog = 10, ReceiveBufferSize = 64 * 1024, //用于接收数据的缓冲区大小,默认为2048。 SendBufferSize = 64 * 1024, //用户发送数据的缓冲区大小,默认为2048。 KeepAliveInterval = 1, //keep alive消息发送时间间隔。单位为秒。 KeepAliveTime = 60, //keep alive失败重试的时间间隔。单位为秒。 SyncSend = false }; SocketServerFactory socketServerFactory = null; //开启wss 使用证书 if (isUseCertificate) { serverConfig.Security = serverSecurity; serverConfig.Certificate = new SuperSocket.SocketBase.Config.CertificateConfig { StoreName = serverStoreName, StoreLocation = System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine, Thumbprint = serverThumbprint }; socketServerFactory = new SocketServerFactory(); } isSetuped = this.WebSocket.Setup(new RootConfig(),serverConfig, socketServerFactory); if (isSetuped) { _Logger.Info("Setup Success..."); } else { _Logger.Error("Failed to setup!"); } this.WebSocket.NewSessionConnected += NewSessionConnected; this.WebSocket.NewMessageReceived += NewMessageReceived; this.WebSocket.SessionClosed += SessionClosed; isSetuped = this.WebSocket.Start(); if (isSetuped) { _Logger.Info("Start Success..."); _Logger.Info("Server Listen at " + this.WebSocket.Listeners[0].EndPoint.Port.ToString()); this._isRunning = true; this._thread = new Thread(new ThreadStart(ProcessMaintainance)); this._thread.Start(); } else { _Logger.Error("Failed to start!"); } } catch (Exception ex) { _Logger.Error(ex.ToString()); } return isSetuped; } /// <summary> /// 消息触发事件 /// </summary> /// <param name="session"></param> /// <param name="value"></param> void NewMessageReceived(WebSocketSession session, string value) { try { _Logger.Info("Receive:" + value.ToString() + " ClientIP:" + session.RemoteEndPoint); if(value.ToString().Equals("IsHere**"))//客户端定时发送心跳,维持链接 { return; } else { MessageReceived?.Invoke(session, value.ToString()); } } catch (Exception e) { _Logger.Error(e.ToString()); } } /// <summary> /// 新链接触发事件 /// </summary> /// <param name="session"></param> void NewSessionConnected(WebSocketSession session) { try { string message = string.Format("New Session Connected:{0}, Path:{1}, Host:{2}, IP:{3}", session.SessionID.ToString(), session.Path, session.Host, session.RemoteEndPoint); _Logger.Info(message); NewConnected?.Invoke(session); } catch (Exception e) { _Logger.Error(e.ToString()); } } /// <summary> /// 客户端链接关闭触发事件 /// </summary> /// <param name="session"></param> /// <param name="value"></param> void SessionClosed(WebSocketSession session, CloseReason value) { string message = string.Format("Session Close:{0}, Path:{1}, IP:{2}", value.ToString(), session.Path,session.RemoteEndPoint); _Logger.Info(message); Closed?.Invoke(session); } #endregion /// <summary> /// 关闭服务端触发事件 /// </summary> public void Dispose() { this._isRunning = false; foreach (WebSocketSession session in this.WebSocket.GetAllSessions()) { session.Close(); } try { this.WebSocket.Stop(); } catch { } } /// <summary> /// 输出实时连接线程 /// </summary> void ProcessMaintainance() { do { try { _Logger.Debug("Display Session Info:" + this.WebSocket.SessionCount); foreach (WebSocketSession session in this.WebSocket.GetAllSessions()) { string message = string.Format("ID:{0}, Remote:{1}, Path:{2}, LastActiveTime:{3}, StartTime:{4}", session.SessionID, session.RemoteEndPoint, session.Path , session.LastActiveTime, session.StartTime); _Logger.Debug(message); } } catch (Exception e) { _Logger.Error(e.ToString()); } System.Threading.Thread.Sleep(5 * 60000); } while (this._isRunning); } /// <summary> /// 发送消息 /// </summary> /// <param name="session">客户端连接</param> /// <param name="message">消息内容</param> public void SendMessage(WebSocketSession session, string message) { Task.Factory.StartNew(() =>{if (session != null && session.Connected) session.Send(message);}); } } }
打开控制台 按顺序安装这几个包
install-package SuperWebSocket
install-package nlog
install-package nlog.config
然后写个业务逻辑类,操作websocket服务端类
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace WebSocketService { public class BLL { WSocketServer _server = null; bool _isRunning = false; public BLL() { try { _server = new WSocketServer(); _server.MessageReceived += Server_MessageReceived; _server.NewConnected += Server_NewConnected; _server.Closed += _server_Closed; } catch (Exception ex) { WSocketServer._Logger.Error(ex.ToString()); } } private void _server_Closed(SuperWebSocket.WebSocketSession obj) { Console.WriteLine($"Closed {System.Web.HttpUtility.UrlDecode(obj.Path, System.Text.Encoding.UTF8)}"); } private void Server_NewConnected(SuperWebSocket.WebSocketSession obj) { //对新链接做处理,验证链接是否合法等等,不合法则关闭该链接 //新链接进行数据初始化 Console.WriteLine($"NewConnected {System.Web.HttpUtility.UrlDecode(obj.Path, System.Text.Encoding.UTF8)}"); } private void Server_MessageReceived(SuperWebSocket.WebSocketSession arg1, string arg2) { //接收到客户端链接发送的东西 Console.WriteLine($"from {System.Web.HttpUtility.UrlDecode(arg1.Path, System.Text.Encoding.UTF8)} => {arg2}"); } public bool Start() { _isRunning = true; //设置监听端口 var result = _server.Open(1234, "MySocket"); //模拟 服务端主动推送信息给客户端 if (result) { Task.Factory.StartNew(() => { while (_isRunning) { foreach (var item in _server.WebSocket.GetAllSessions()) _server.SendMessage(item,"服务器时间:"+DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); System.Threading.Thread.Sleep(1000); } }); } return result; } public void Stop() { _isRunning = false; _server.Dispose(); } } }
然后就是在Windows服务停启时操作业务逻辑
好了 一个c# websocket 服务端搭建完成了
因为这里是通过控制台来调用调试这个服务,所以要再建一个控制台项目
然后选中控制台项目,ctrl+f5,启动项目,如果没什么问题,那么就搞定了,注意websocket监听的端口是可用的,我这里用了1234
2.客户端-控制台
接下来就建个控制台项目作为客户端,去连接服务端
新建控制台项目,把websocket客户端类拷进去
using SuperSocket.ClientEngine; using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Net.WebSockets; using System.Text; using System.Threading; using System.Threading.Tasks; using WebSocket4Net; //install-package WebSocket4Net //install-package nlog //install-package nlog.config namespace WebSocketClient { public class WSocketClient:IDisposable { //日志管理 public static NLog.Logger _Logger = NLog.LogManager.GetCurrentClassLogger(); #region 向外传递数据事件 public event Action<string> MessageReceived; #endregion WebSocket4Net.WebSocket _webSocket; /// <summary> /// 检查重连线程 /// </summary> Thread _thread; bool _isRunning = true; /// <summary> /// WebSocket连接地址 /// </summary> public string ServerPath { get; set; } public WSocketClient(string url) { ServerPath = url; this._webSocket = new WebSocket4Net.WebSocket(url); this._webSocket.Opened += WebSocket_Opened; this._webSocket.Error += WebSocket_Error; this._webSocket.Closed += WebSocket_Closed; this._webSocket.MessageReceived += WebSocket_MessageReceived; } #region "web socket " /// <summary> /// 连接方法 /// <returns></returns> public bool Start() { bool result = true; try { this._webSocket.Open(); this._isRunning = true; this._thread = new Thread(new ThreadStart(CheckConnection)); this._thread.Start(); } catch (Exception ex) { _Logger.Error(ex.ToString()); result = false; } return result; } /// <summary> /// 消息收到事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void WebSocket_MessageReceived(object sender, MessageReceivedEventArgs e) { _Logger.Info(" Received:" +e.Message); MessageReceived?.Invoke(e.Message); } /// <summary> /// Socket关闭事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void WebSocket_Closed(object sender, EventArgs e) { _Logger.Info("websocket_Closed"); } /// <summary> /// Socket报错事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void WebSocket_Error(object sender, ErrorEventArgs e) { _Logger.Info("websocket_Error:" + e.Exception.ToString()); } /// <summary> /// Socket打开事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void WebSocket_Opened(object sender, EventArgs e) { _Logger.Info(" websocket_Opened"); } /// <summary> /// 检查重连线程 /// </summary> private void CheckConnection() { do { try { if (this._webSocket.State != WebSocket4Net.WebSocketState.Open && this._webSocket.State != WebSocket4Net.WebSocketState.Connecting) { _Logger.Info(" Reconnect websocket WebSocketState:" + this._webSocket.State); this._webSocket.Close(); this._webSocket.Open(); Console.WriteLine("正在重连"); } } catch (Exception ex) { _Logger.Error(ex.ToString()); } System.Threading.Thread.Sleep(5000); } while (this._isRunning); } #endregion /// <summary> /// 发送消息 /// </summary> /// <param name="Message"></param> public void SendMessage(string Message) { Task.Factory.StartNew(() => { if (_webSocket != null && _webSocket.State == WebSocket4Net.WebSocketState.Open) { this._webSocket.Send(Message); } }); } public void Dispose() { this._isRunning = false; try { _thread.Abort(); } catch { } this._webSocket.Close(); this._webSocket.Dispose(); this._webSocket = null; } } }
同样打开包管理控制台,顺序安装这几个必要的包,注意选择安装的项目名字
install-package WebSocket4Net
install-package nlog
install-package nlog.config
装完就可以开始连接服务端了
3.客户端-网页
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta charset="utf-8" /> <title></title> </head> <body> <div id="onMessage" style="width:100%;height:200px;overflow-y:scroll;"> </div> <input type="text" id="input" /><input id="sendMessage" type="button" value="发送" /> </body> </html> <script> //websocket 类 var myWS = function () { this.ws = null; this.url = null; this.onmessage = function () { }; this.onopen = function () { }; this.onclose = function () { }; this.onerror = function () { }; }; myWS.prototype.sendMessage = function (message) {//客戶端發送消息到服務器方法 if (this.ws != null && this.ws.readyState == 1) { this.ws.send(message); } }; myWS.prototype.start = function () {//啟動鏈接 this.connect(); this.conncheckstatus(); this.heartbeat(); }; //心跳 myWS.prototype.heartbeat = function () { var obj = this; if (obj.ws != null && obj.ws.readyState == 1) { var message = "IsHere**"; obj.ws.send(message); } setTimeout(_=>obj.heartbeat(), 300000); }; myWS.prototype.conncheckstatus = function () { var obj = this; if (obj.ws != null && obj.ws.readyState != 0 && obj.ws.readyState != 1) { obj.connect(); } setTimeout(_=>obj.conncheckstatus(), 5000); }; myWS.prototype.connect = function () { this.disconnect(); //WebSocket地址 if (this.url != null && this.url != "") { try { if ("WebSocket" in window) { this.ws = new WebSocket(this.url); } else if ("MozWebSocket" in window) { this.ws = new MozWebSocket(this.url); } else { alert("browser not support websocket"); } if (this.ws != null) { var that = this; this.ws.onopen = function (event) { that.onopen(event); }; this.ws.onmessage = function (event) { that.onmessage(event); }; this.ws.onclose = function (event) { that.onclose(event); }; this.ws.onerror = function (event) { that.onerror(event); }; } } catch (ex) { console.log("connect:" + ex); } } }; myWS.prototype.disconnect = function () { if (this.ws != null) { try { this.ws.close(); this.ws = null; } catch (ex) { this.ws = null; } } }; </script> <script> var _ws = new myWS(); _ws.url = 'ws://192.168.1.13:1234/lcj网页'; //注册接收服务端消息的方法 服务端数据位于event.data字段 _ws.onmessage = (event) => { document.getElementById('onMessage').innerHTML += event.data + '<br/>'; document.getElementById('onMessage').scrollTop = document.getElementById('onMessage').scrollHeight; }; //启动链接 _ws.start(); document.getElementById('sendMessage').addEventListener('click', () => { //客户端发送消息到服务端 _ws.sendMessage(document.getElementById('input').value); document.getElementById('input').value = ''; }); </script>
完成…
源代码下载 百度盘
链接: https://pan.baidu.com/s/1JljNBFhCWSUrtfohDbNpDA 提取码: gyj7
Windows服务安装方法
1.把项目模式改成发布模式Release
2.右键项目生成或者重新生成
3.打开项目位置,打开bin文件夹,打开Release文件夹
4.把服务必备的一些组件都复制走
安装完成,在计算机管理-服务里面可以看到,你的服务名字,还没启动,需要手动开启,或者电脑重启后自动开启
右键服务-选择第一个“启动”
卸载服务,先打开服务管理,右键,停止,然后复制删除命令到cmd执行
刷新一下服务列表,服务已经删除
如果想要更新服务的话,要先停止服务,然后把生成后的新dll啊或者exe,覆盖掉旧的就可以了,修改配置文件的话也需要重新启动服务才能生效,停止服务需要一点时间,不能一点停止就立即覆盖,系统会报文件占用
所有步骤都完成了
这里是安装服务的工具和命令
链接: https://pan.baidu.com/s/1xBAzOcVdRmJfqaN8oCRXow 提取码: ae5z
WSS 开启介绍
add 2019年1月25日18:06:47
各参数说明,这里可以有两种方式使用证书
1.是填证书安装后的存储区名字和证书的指纹
2.是直接填证书的所在路径,和密码
目前啊 我只成功地用过路径,和密码的方式开启,
关于怎么用指纹,我还是不知道,如有哪位知道的,望相告.
另外开了wss后,需要用域名来访问,ip不行
(以上结论来于,阿里云免费试用服务器个人版 win server 2008 r2 和免费国外域名 和 阿里云上申请的免费 ssl证书…)
/// <summary> /// 开启服务端 /// </summary> /// <param name="port">123</param> /// <param name="serverName">test</param> /// <param name="isUseCertificate">true 如果开启wss需要用域名访问(wss:\\abc.com:123\)</param> /// <param name="certificateStoreName">My -证书安装后的存储位置(一般是“个人”)</param> /// <param name="security">ssl/tls</param> /// <param name="certificateThumbprint">7384a6027fa8004585c0958c7fcbcb8fd9cd27fb 证书指纹 如果指纹填空,则使用路径加载证书,否则使用指纹</param> /// <param name="certificatePath">D:\1774183_xxx_iis\1774183_xxx.pfx 证书所在路径</param> /// <param name="certificatePwd">ABC 证书密码</param> /// <returns></returns> public bool Open(int port, string serverName, bool isUseCertificate = false, string certificateStoreName = "", string security = "", string certificateThumbprint = "",string certificatePath="",string certificatePwd="") { bool isSetuped = false; try { this.WebSocket = new WebSocketServer(); var serverConfig = new ServerConfig { Name = serverName, MaxConnectionNumber = 10000, //最大允许的客户端连接数目,默认为100。 Mode = SocketMode.Tcp, Port = port, //服务器监听的端口。 ClearIdleSession = false, //true或者false, 是否清除空闲会话,默认为false。 ClearIdleSessionInterval = 120,//清除空闲会话的时间间隔,默认为120,单位为秒。 ListenBacklog = 10, ReceiveBufferSize = 64 * 1024, //用于接收数据的缓冲区大小,默认为2048。 SendBufferSize = 64 * 1024, //用户发送数据的缓冲区大小,默认为2048。 KeepAliveInterval = 1, //keep alive消息发送时间间隔。单位为秒。 KeepAliveTime = 60, //keep alive失败重试的时间间隔。单位为秒。 SyncSend = false }; SocketServerFactory socketServerFactory = null; //开启wss 使用证书 if (isUseCertificate) { serverConfig.Security = security; //指纹不为空 则使用指纹,否则使用路径访问证书 if (certificateThumbprint != string.Empty) { serverConfig.Certificate = new SuperSocket.SocketBase.Config.CertificateConfig { StoreName = certificateStoreName, StoreLocation = System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine, Thumbprint = certificateThumbprint }; } else { serverConfig.Certificate = new SuperSocket.SocketBase.Config.CertificateConfig { FilePath = certificatePath, Password = certificatePwd }; } socketServerFactory = new SocketServerFactory(); } isSetuped = this.WebSocket.Setup(new RootConfig(),serverConfig, socketServerFactory); if (isSetuped) { _Logger.Info("Setup Success..."); } else { _Logger.Error("Failed to setup!"); } this.WebSocket.NewSessionConnected += NewSessionConnected; this.WebSocket.NewMessageReceived += NewMessageReceived; this.WebSocket.SessionClosed += SessionClosed; isSetuped = this.WebSocket.Start(); if (isSetuped) { _Logger.Info("Start Success..."); _Logger.Info("Server Listen at " + this.WebSocket.Listeners[0].EndPoint.Port.ToString()); this._isRunning = true; this._thread = new Thread(new ThreadStart(ProcessMaintainance)); this._thread.Start(); } else { _Logger.Error("Failed to start!"); } } catch (Exception ex) { _Logger.Error(ex.ToString()); } return isSetuped; }
这里我使用配置文件
源码地址链接: https://pan.baidu.com/s/19DbRZLXicwMJBKfkM0HJeQ 提取码: xnf2
-----------------------------------------------------2020年4月9日14:13:05
可自行修改依赖目标框架
SuperWebSocket源码 链接: https://pan.baidu.com/s/1_brs_DL-Rx6AkLXz9KVVGA 提取码: 3rui
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。