c# SuperWebSocket服务端,html WebSocket客户端,c# WebSocket4Net 客户端 的使用
c# superwebsocket服务端可以寄宿在控制台程序、窗体程序、Windows服务
c# websocket客户端可以是控制台程序、窗体程序、Windows服务、html、手机,能连上websocket的就行了
服务端可以开启wss安全链接
如果想做即时通讯,双工通讯,或者因为频繁发送http请求导致的web服务器承受不住,都可以转用websocket
websocket 有良好的交互体验,快速的数据传输
websocket 开发简单,部署方便,上手没难度
我这里展示了,把websocket服务端寄宿在Windows服务里,客户端则用控制台访问和用web访问,调试阶段,为了避免频繁停启Windows服务,所以我用控制台启动了服务端,生产环境就可以直接把exe执行文件注册成服务了
底部有源代码百度盘下载
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;
setTimeout(function () {
if (obj.ws != null && obj.ws.readyState == 1) {
var message = "IsHere**";
obj.ws.send(message);
}
setTimeout(arguments.callee, 300000);
}, 10);
};
myWS.prototype.conncheckstatus = function () {
var obj = this;
setTimeout(function () {
if (obj.ws != null && obj.ws.readyState != 0 && obj.ws.readyState != 1) {
obj.connect();
}
setTimeout(arguments.callee, 5000);
}, 15);
};
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