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 MessageReceived;
public event Action NewConnected;
public event Action Closed;
#endregion
public WebSocketServer WebSocket;
Thread _thread;
bool _isRunning = true;
public WSocketServer()
{
}
#region WebSockertServer
///
/// 开启服务端
///
///
///
///
///
///
///
///
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;
}
///
/// 消息触发事件
///
///
///
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());
}
}
///
/// 新链接触发事件
///
///
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());
}
}
///
/// 客户端链接关闭触发事件
///
///
///
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
///
/// 关闭服务端触发事件
///
public void Dispose()
{
this._isRunning = false;
foreach (WebSocketSession session in this.WebSocket.GetAllSessions())
{
session.Close();
}
try
{
this.WebSocket.Stop();
}
catch { }
}
///
/// 输出实时连接线程
///
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);
}
///
/// 发送消息
///
/// 客户端连接
/// 消息内容
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 MessageReceived;
#endregion
WebSocket4Net.WebSocket _webSocket;
///
/// 检查重连线程
///
Thread _thread;
bool _isRunning = true;
///
/// WebSocket连接地址
///
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 "
///
/// 连接方法
///
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;
}
///
/// 消息收到事件
///
///
///
void WebSocket_MessageReceived(object sender, MessageReceivedEventArgs e)
{
_Logger.Info(" Received:" +e.Message);
MessageReceived?.Invoke(e.Message);
}
///
/// Socket关闭事件
///
///
///
void WebSocket_Closed(object sender, EventArgs e)
{
_Logger.Info("websocket_Closed");
}
///
/// Socket报错事件
///
///
///
void WebSocket_Error(object sender, ErrorEventArgs e)
{
_Logger.Info("websocket_Error:" + e.Exception.ToString());
}
///
/// Socket打开事件
///
///
///
void WebSocket_Opened(object sender, EventArgs e)
{
_Logger.Info(" websocket_Opened");
}
///
/// 检查重连线程
///
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
///
/// 发送消息
///
///
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
完成…
源代码下载 百度盘
链接: 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证书…)
///
/// 开启服务端
///
/// 123
/// test
/// true 如果开启wss需要用域名访问(wss:\\abc.com:123\)
/// My -证书安装后的存储位置(一般是“个人”)
/// ssl/tls
/// 7384a6027fa8004585c0958c7fcbcb8fd9cd27fb 证书指纹 如果指纹填空,则使用路径加载证书,否则使用指纹
/// D:\1774183_xxx_iis\1774183_xxx.pfx 证书所在路径
/// ABC 证书密码
///
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