一.认识SingalR
1.Http协议是浏览器端主动发请求,服务器不能主动发起请求。可以使用ajax或者原生websocket开发,但是难度大。但是使用SignalR,简化了WebSocket开发。
2.SignalR集线器类(SignalR持久连接)是底层机制。
3.可以实现即时通讯。SignalR有三种传输模式:LongLooping(长轮询)、WebSocket(HTML5的WEB套接字)、Forever Frame(隐藏框架的长请求连接)
二.编写代码
1.前端代码
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>OnLineUser</title>
@*注意这个文件是动态创建的,引入的时候尽量放在最后,还有jq和singalR的引入最好按顺序进行引入否则可能会报错*@
<script src="~/Scripts/jquery-3.3.1.js">
</script>
<script src="~/Scripts/jquery.signalR-2.2.2.js"></script>
<script src="~/signalr/hubs" type="text/javascript"></script>
</head>
<body>
<input type="text" id="userName" />
<input type="button" value="click" id="btnlogin" />
<script>
$('#btnlogin').click(function(){
var username=$('#userName').val();
$.connection.onLineUserHub.server.login(username);
});
$.connection.onLineUserHub.client.onOnlineUserStatusChange=function(msg)
{
var str = val == ture ? "在线" : "不在线";
alert(key+"的状态是" + str);
}
$.connection.hub,start().done(function(){
alert("开启成功Start");
}).fail(function(){
alert("启动失败");
})
</script>
</body>
</html>
2.后端Hub(TestHub)代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using Microsoft.AspNet.SignalR;
using StackExchange.Redis;
using System.IO;
using System.Text;
namespace SingalRProject
{
public class OnLineUserHub:Hub
{
public async Task Login(string userName)
{
using(ConnectionMultiplexer redis=ConnectionMultiplexer.Connect("localhost:6379"))
{
IDatabase db=readis.GetDatabase();
RedisKey strs="key"+this.ContextConnectionId;
var str=await db.StringGetAsync(strs);
if(str.ToString()==userName)
{
await OnDisConectionted(false);
return;
}
var db.StringSetAsync("key"+UserName,true);
await db.StringSetASync("key_UserName"+this.Context.ConnectionId,userName);
await db.SetAddAsync("key_User",UserName);
RedisValue[]userNames=await db.SetMemberAsync("Key_User");
ReduisKey[]userNamesOnlineKeys=userNames.Select(e=>(RedisKey)("key"+e)).ToArray();
Dictionary<string,bool>data=new Dictionary<strung,bool>();
for(int i=0lu<userNames.Length;i++)
{
data[userNames[i]]=(bool)userStatuses[i];
}
Clients.AllonOnlienUsersStatusChange(data);
}
}
public override async Task OnDisconnected(bool stopCalled)
{
using(ConnectionMultiplexer redis=ConnectionMultiplexer,Connect("localhost:6379"))
{
IDatabase db=redis.GetData();
string userName=await db.StringGetAsync("key"+this,Context.ConnectionId);
await db.StringSetAsync("key"+UserName,false);
}
}
}
}
//升级版
namespace SingalRProject
{
public class OnLineUserHub:HUb
{
private static connStr="localhost:6379"
private Object obj=new Object;
private static ConnectionMultiplexer redis;
private static ConnectionMultiplexer _regist
{
get
{
if(redis==null)
{
lock(obj)
{
if(redis==null||redis.IsConnected)
{
redis=redis.Connect(connStr);
}
return redis;
}
}
}
}
public async Task<IDatabase> Db()
{
return _redis.GetDatabase();
}
}
}
捕获SignalR的异常
public class ExceptoinHubPipelineMoudule:HubPipelineModule
{
protected override void OnIncomingError(ExceptionContext exceptionContext,IHubIncomingInvokerContext invokerContext)
{
//可以把异常计入到日志中
base.OnIncomingError(exceptionContext,invokerContext);
//exceptionContext.Error就是一个异常对象 可以记录到日志里面 记录到分布式的日志
WriteLog(exceptionContext.Error.Message);
dynamic caller=invokerContext.Hub.Clients.Callser;
//把异常信息传递出去
caller.onServerError(exceptionContext.Error.Message);
}
private static string path=@"XXXXX";
public void WriteLog(string ErrorInfo)
{
using(Stream fs=new FileStream(path,FileMode.OpenOrCreate))
{
byte[]info=Encoding.UTF8.GetBytes(ErrorInfo);
fs.Write(info,0,info.Length);
}
}
}
//接着再Global.asax.cs中进行全局的注册
namespace SignalProhect
{
public class MvcApplication:Syste.Web.HttpApplication
{
proteted void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Route);
//进行全局注册SignalR异常捕获
GlobalHost.HubPipeline.AddModule(new HubException());
}
}
}
接下来进行组的添加和删除,在同一组内可以互相进行通信
public class GroupHub:Hub
{
public void AddGroup(string groupName)
{
Groups.Add(this.Context.ConnectionId,groupName);
Clients.All.Hello();
}
public void SendGroupMsg(string grouName,string msg)
{
Clients.OthersInGroup(grouName).onMessage(msg);
Clients.OthersInGroup(grouName).OnMessage2(msg)
}
}
前端页面
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title></title>
<script src="~/Scripts/jquery-3.3.1.js">
</script>
<script src="~/Scripts/jquery.signalR-2.2.2.js"></script>
<script src="~/signalr/hubs" type="text/javascript"></script>
</head>
<body>
<div id="msgs">
消息:
<ul>
</ul></div>
<div id="msg">
组名:<input type="text" id="groupName1"/>
<button id="btnAddGroup">加入组</button>
组名:<input type="text" id="groupName2" />
消息:<input type="text" id="message" />
<button id="btnSendMsg">发送消息</button>
</div>
<script type="text/javascript">
$.connection.groupHub.client.onMessage = function (msg) {
$("<li>收到消息1" + msg + "</li>").appendTo("#msgs");
}
$.connection.groupHub.client.onMessage2 = function (msg) {
$("<li>收到消息1" + msg + "</li>").appendTo("#msgs");
}
$.connection.hub.start().done(function () {
$("<li>启动" + "成功"+ "</li>").appendTo("#msgs");
}).fail(function () {
alert("开启失败");
});
$('#btnAddGroup').click(function () {
var groupName = $('#groupName1').val();
//var message = $('#message').val();
$.connection.groupHub.server.addGroup(groupName);
});
$('#btnSendMsg').click(function () {
var groupName = $('#groupName2').val();
var message = $('#message').val();
$.connection.groupHub.server.sendGroupMsg(groupName, message);
}).fail(function () {
alert("调用失败");
})
</script>
</body>
</html>