(二)SuperSocket(webapi后端+webform前端)

前端页面逻辑

<body>
<div>
<div><span>提示:</span><span id="j_notice"></span></div>
<div><span>提示:</span><span id="j_heart"></span></div>
<div><span>提示:</span><span id="j_wlyc"></span></div>
<div style="margin-top: 20px">
<input type="text" name="name" value="" placeholder="请输入登录标识" id="j_userKey" />
<button id="j_close">关闭连接</button>
</div>
<div style="margin-top: 20px">
<input type="text" value="" placeholder="请输入发送内容" id="j_content" />
<button id="j_send">群发</button>
</div>

<div style="margin-top: 20px">
<input type="text" value="" placeholder="请输入接收人标识" id="j_receiveUserKey" />
<button id="j_send2">单发</button>
</div>
<div>
<ul id="j_Msg"></ul>
</div>
</div>
</body>

 

前端js逻辑

(function (w) {

//(一)心跳检测,检测后端是否还可以链接

var heartCheck = {//心跳检测
timeout: 10000,
timeoutObj: null,
servetTimeoutObj: null,
start: function () {
var self = this;
this.timeoutObj && clearTimeout(this.timeoutObj);//如果不加this.timeoutObj &&,clearTimeout以后timeoutObj对象就不存在了,再次setTimeout时就会因找不到对象报错
this.servetTimeoutObj && clearTimeout(this.servetTimeoutObj);//同上
this.timeoutObj = setTimeout(function () {

//10秒后执行,执行成功后,在ws.onmessage里面调用heartCheck.start();继续心跳检测,此时clearTimeout(this.servetTimeoutObj)下面的servetTimeoutObj就被清掉了,不会执行了

//如果执行失败,就不会调用heartCheck.start();不会执行clearTimeout(this.servetTimeoutObj),就会打印 您暂时无法获取服务端推送的最新消息,请检查网络是否异常! 这句话
ws.send("heartcheck");

self.servetTimeoutObj = setTimeout(function () {
$("#j_heart").append("您暂时无法获取服务端推送的最新消息,请检查网络是否异常!")
ws.close();
//google(会进onclose函数),在onclose里面调用重连方法mainUitls.reconnect();,重连失败进入onerror函数,在onerror里面反复重连操作如果没连上
//ie
//直接进入onerror函数,在reconnect函数李设定的时间后再次从连
}, self.timeout)
}, this.timeout)

}
}

//声明全局对象
var ws;
var lockReconnect = false;
var tt = null;
var mainUitls = {

//(二)初始话基本事件

init: function (dom) {
this.createWebsocket(dom);
this.initClick();

},

//(三)重连操作

reconnect: function () {
if (lockReconnect) {//防止多次创建链接,只有当一个链接创建有了结果才允许下次创建,防止多次执行创建链接的操作(被多个事件执行调用)
return;
};
lockReconnect = true;
tt && clearTimeout(tt);//将tt设置为underfind,如果直接clearTimeout(tt) ,tt就被清掉不存在了,下次给tt赋值就会报错
tt = setTimeout(function () {//进入该方法20秒后进行重连,链接失败后在进入ws.onerror继续重连
mainUitls.createWebsocket($("#j_userKey").val());
lockReconnect = false;
}, 20000)
},

//(四)创建长链接,以及跟链接相关的事件

createWebsocket: function (dom) { 

//1:建立长链接:

ws = new WebSocket('ws://192.168.2.117:8201');//就是后端的ip,8200就是后端的端口

//2:链接成功后要做心跳检测

ws.onopen = function () {
$('#j_notice').html('已经连接');
ws.send(dom + "--userid");//链接成功后把当前用户id推上去(windows服务不能传参,所以只能链接成功后推上去)
heartCheck.start();//开始心跳检测
}

//3:接收服务端或者其他客户端推送过来的消息

ws.onmessage = function (evt) {
if (evt.data == "heartchecksuccess") {
$("#j_heart").append("<li>链接正常</li>");
heartCheck.start();//接受到服务器信息表示链接是通的,过一会儿再次进行心跳检测
} else {
$("#j_Msg").append("<li>" + evt.data + "</li>");
}
}

//4:网络异常后过一会需要重连操作,就是突然网络就好了

ws.onerror = function (evt) {
$('#j_wlyc').append("链接出现异常,请检查网络!");
mainUitls.reconnect();
}

//5:链接关闭后要执行的函数,比如很久没得到服务器的响应,可以暂时断开,过一会在进行链接reconnect();

ws.onclose = function () {
$('#j_notice').html("连接断开");
mainUitls.reconnect();
}

},

//(五)各种点击事件

initClick: function () {

//1:关闭链接

$("#j_close").on("click", function () {
ws.close();
});

//2:群发消息

$("#j_send").on("click", function () {
if ($("#j_userKey").val() == "") {
$('#j_notice').html("请输入用户标识");
return;
}
//表示与服务器已经建立好连接
if (ws.readyState == WebSocket.OPEN) {
var content = $("#j_userKey").val() + "--alluser" + $('#j_content').val();
ws.send(content);
}
//表示与服务器连接已经断开
else if (ws.readyState == WebSocket.CLOSED) {
$('#j_notice').html('与服务器连接已经断开');
}
//表示正在尝试与服务建立连接
else if (ws.readyState == WebSocket.CONNECTING) {
$('#j_notice').html('正在尝试与服务建立连接');
}
//正在关闭与服务器连接
else if (ws.readyState == WebSocket.CLOSING) {
$('#j_notice').html('正在关闭与服务器连接');
}

});

//3:单发消息

$("#j_send2").on("click", function () {
if ($("#j_userKey").val() == "") {
$('#j_notice').html("请输入登陆标识");
return;
}
var reciveiduser = $('#j_receiveUserKey').val();
if (reciveiduser == "") {
$('#j_notice').html('请输入接收人的标识');
return;
}
//下面对内容进行拼接
var loginuser = $("#j_userKey").val();
var finalMsg = loginuser + "--touserid" + reciveiduser + "--touserid" + $('#j_content').val();
//表示与服务器已经建立好连接
if (ws.readyState == WebSocket.OPEN) {
ws.send(finalMsg);

}
//表示与服务器连接已经断开
else if (ws.readyState == WebSocket.CLOSED) {
$('#j_notice').html('与服务器连接已经断开');
}
//表示正在尝试与服务建立连接
else if (ws.readyState == WebSocket.CONNECTING) {
$('#j_notice').html('正在尝试与服务建立连接');
}
//正在关闭与服务器连接
else if (ws.readyState == WebSocket.CLOSING) {
$('#j_notice').html('正在关闭与服务器连接');
}

});

}

 

};

w.mainUitls = mainUitls;
})(window)

//(六)初始化方法,并生成随机数据的用户标识

$(function () {
var dom1 = Math.ceil(Math.random() * 10);//6;
$("#j_userKey").val(dom1)
mainUitls.init(dom1);

});

 

后端逻辑

//在web.config里面添加

<add key="APWebSocketIP" value="192.168.2.117" />
<add key="APWebSocketPort" value="8201" />

后端初始化发送消息的类

public static class SuperWebsocketTest
{
public static void Int()
{

string ip = ConfigurationManager.AppSettings["APWebSocketIP"].ToString();
string port = ConfigurationManager.AppSettings["APWebSocketPort"].ToString();
SuperWebSocket.WebSocketServer server = new SuperWebSocket.WebSocketServer();
if (!server.Setup(ip, int.Parse(port)))
{
//处理启动失败消息
return;
}

server.NewSessionConnected += WebSocketServer_NewSessionConnected;//用户上线
server.SessionClosed += WebSocketServer_SessionClosed;//用户下线
server.NewMessageReceived += WebSocketServer_NewMessageReceived;//接收消息


if (!server.Start())
{
string mst=string.Format("开启WebSocket服务侦听失败:{0}:{1}", server.Config.Ip, server.Config.Port);//监听错误信息可以写入日志
//处理监听失败消息
return;
}
}
/// <summary>
/// 接收消息
/// </summary>
/// <param name="session"></param>
/// <param name="value">WriteLog(websocketObj.userid);</param>
private static void WebSocketServer_NewMessageReceived(WebSocketSession session, string value)
{

if (value.Contains("--userid"))
{
#region ws.onopen第一次,把userid发送给服务端存起
WebsocketObj websocketObj = new WebsocketObj();
websocketObj.userid = value.Replace("--userid", "");
websocketObj.webSocket = session;
WebManager.AddWebsocket(websocketObj);//添加连接池
#region 用户链接成功,表示用户已经上线
string remote_ip = ((System.Net.IPEndPoint)session.RemoteEndPoint).Address.MapToIPv4().ToString();//获取远程连接IP
string msg=string.Format("WebSocketManager:用户{0} {1}上线", value.Replace("--userid", ""), remote_ip);//可以些如日志
#endregion
#endregion

}
else if (value.Contains("--touserid"))
{

#region 给单个用户发送信息
var array = value.Split(new string[] { "--touserid" }, StringSplitOptions.None);
string currentuserid = array[0];//当前得用户id
string recieveuserid = array[1];//接收人得用户id
string msg = array[2];//接收得内容
string errpr;
msg = currentuserid + "发来消息:" + msg;
WebManager.SendToSimple(recieveuserid, msg, out errpr);
if (!string.IsNullOrWhiteSpace(errpr))
{
string msg=errpr;//发送异常打印异常信息
}
#endregion
}
else if (value.Contains("heartcheck"))//心跳检测
{

session.Send("heartchecksuccess");//给客户端回复信息,表示客户端和服务端还能相互通讯
}
else
{
#region 群发消息
var array = value.Split(new string[] { "--alluser" }, StringSplitOptions.None);
string currentuserid = array[0];//当前得用户id
string msg = array[1];//接收得内容
string errpr;
msg = currentuserid + "发来消息:" + msg;
WebManager.SendToAll(currentuserid, msg, out errpr);
if (!string.IsNullOrWhiteSpace(errpr))
{
//WriteLog(errpr);//发送异常打印异常信息
}
#endregion
}


}

/// <summary>
/// 用户下线
/// </summary>
/// <param name="session"></param>
/// <param name="value"></param>
private static void WebSocketServer_SessionClosed(WebSocketSession session, SuperSocket.SocketBase.CloseReason value)
{

string remote_ip = ((System.Net.IPEndPoint)session.RemoteEndPoint).Address.MapToIPv4().ToString();//获取远程连接IP
string msg=string.Format("WebSocketManager:{0} {1}下线", value, remote_ip);//可以写入日志

}
/// <summary>
/// 用户上线
/// </summary>
/// <param name="session"></param>
private static void WebSocketServer_NewSessionConnected(WebSocketSession session)
{

string remote_ip = ((System.Net.IPEndPoint)session.RemoteEndPoint).Address.MapToIPv4().ToString();//获取远程连接IP
string msg=string.Format("WebSocketManager:{0} 上线",  remote_ip);//可以写入日志

}
}

 

发送消息的底层类

public class WebManager
{
public static List<WebsocketObj> websocketObjs = new List<WebsocketObj>();
/// 用户第一次链接,添加链接池
public static void AddWebsocket(WebsocketObj websocketObj)
{
websocketObjs.Add(websocketObj);
}
/// 单发消息
public static void SendToSimple(string userid, string msg, out string error)
{
error = "";
List<WebsocketObj> websocketObjs1 = websocketObjs.Where(m => m.userid == userid).ToList();
if (websocketObjs1.Count > 0)
{
for (int i = 0; i < websocketObjs1.Count; i++)
{
try
{
websocketObjs1[i].webSocket.Send(msg);
}
catch (Exception e)
{
error = websocketObjs1[i].userid + ":" + e.Message;//如果出现异常
}

}
}

}
/// 群发消息
public static void SendToAll(string userid, string msg, out string error)
{
error = "";
List<WebsocketObj> websocketObjs1 = websocketObjs.Where(m => m.userid != userid).ToList();
if (websocketObjs1.Count > 0)
{
for (int i = 0; i < websocketObjs1.Count; i++)
{
try
{
websocketObjs1[i].webSocket.Send(msg);
}
catch (Exception e)
{
error = websocketObjs1[i].userid + ":" + e.Message;//如果出现异常
}

}
}

}

}

socket类

public class WebsocketObj
{
public string userid { get; set; }
public WebSocketSession webSocket { get; set; }
}

非服务器iis对最大长连接的限制个数为10,修改呢个限制的方法是在iis的应用程序池-设置应用程序池默认设置-进程模型-最大工作进程数进行修改

posted @   yingxianqi  阅读(255)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端
点击右上角即可分享
微信分享提示