目录:
- SignalR概念
- 基本使用
- 对点聊天
1.SignalR
是微软为实现实时通信而开发的一个类库。可进行分布式实时通信,远程代理实现。
1.1 两大内部对象
- Persisten Connection
用于客户端和服务器端的持久连接。
- Hub(集线器)对象
用于信息交互,将服务器端的数据推送(push)至客户端。
原理:客端建立与服端的连接。客端调用服端的方法。服端通过客端发送的请求,响应数据,调用客端的方法将数据推送至客端。
1.2 基本使用
- 创建一个MVC应用程序。
- 在MVC项目的Models文件夹中添加新项 SignalR Hub集线器类。
在创建的Hub类中添加如下代码:
//hub别名,方便前台调用
[HubName("getMsg")]
public class MyHub : Hub
{
public void Send(string title,string msg)
{
//调用客户端的sendMessage()方法
Clients.All.sendMessage(title,msg); //其中Clients.All是dynamic类型,sendMessaage()方法是视图中js定义的function。
}
}
- 在项目中添加 OWIN StartUp 类。
public class Startup
{
public void Configuration(IAppBuilder app)
{
//注册管道,使用默认的虚拟地址,根目录下的"/signalr",
//当然你也可以自己定义
app.MapSignalR();
}
}
- 创建控制器和视图
//创建MessageController,并创建两个用于显示视图的action。
//控制器代码:
ublic class MessageController : Controller
{
//发送消息
public ActionResult SendMessage()
{
return View();
}
//接收消息
public ActionResult ReceiveMessage()
{
return View();
}
}
//发送消息视图代码:
<h2>发送消息</h2>
<div>
标题:<input type="text" id="title" />
</div><br />
<div>
内容:<textarea id="message" rows="4" cols="30"></textarea>
</div>
<br />
<div>
<input type="button" id="sendmessage" value="发送" />
</div>
<script src="~/Scripts/jquery.signalR-2.2.2.js"></script>
<!--引用自动生成的SignalR 集线器(Hub)脚本.在运行的时候在浏览器的Source下可看到 -->
<script src="~/signalr/hubs"></script>
<script type="text/javascript">
$(function () {
// 引用自动生成的集线器代理(此处使用别名getMsg)
var chat = $.connection.getMsg;
// 集成器连接开始
$.connection.hub.start().done(function () {
// 服务连接完成,给发送按钮注册单击事件
$('#sendmessage').click(function () {
// 调用服务器端集线器的Send方法
chat.server.send($("#title").val(), $('#message').val()); //又调用了客户端,客户端的函数就是添加信息列,就实现了广播消息功能
});
});
});
</script>
//接收消息视图代码:
<h2>接收消息</h2>
<div>
<br />
<div id="msgcontent"></div>
</div>
<script src="~/Scripts/jquery.signalR-2.2.2.js"></script>
<script src="~/signalr/hubs"></script>
<script type="text/javascript">
$(function () {
// 引用自动生成的集线器代理
var chat = $.connection.getMsg;
// 定义服务器端调用的客户端sendMessage来显示新消息
chat.client.sendMessage = function (title, message) {
// 向页面发送接收的消息
var html = "<div>标题:" + title + "消息内容:" + message + "</div>";
$("#msgcontent").after(html);
};
// 集成器连接开始
$.connection.hub.start(); //与SignalR服务建立连接
});
</script>
//<!--引用SignalR库. -->
<!--引用SignalR库. -->
<script src="~/Scripts/jquery.signalR-2.2.0.min.js"></script>
<!--引用自动生成的SignalR 集线器(Hub)脚本 -->
<script src="~/signalr/hubs"></script>
1.3 实现点对点聊天
Clients对象的所有属性或方法,具体的定义如下:
public interface IHubConnectionContext<T> { T All { get; } // 代表所有客户端 T AllExcept(params string[] excludeConnectionIds); //除了参数中的所有客户端 T Client(string connectionId); // 特定的客户端,实现端对端聊天的关键 T Clients(IList<string> connectionIds); // 参数中的客户端 T Group(string groupName, params string[] excludeConnectionIds); // 指定客户端组,可以实现群聊 T Groups(IList<string> groupNames, params string[] excludeConnectionIds); T User(string userId); // 特定的用户 T Users(IList<string> userIds); // 参数中的用户 }
SignalR会每一个客户端分配一个ConnnectionId
实现思路:
- 客户端登入的时候记录下客户端的ConnnectionId,并将用户加入到一个静态数组中,该数据为了记录所有在线用户。
- 用户可以点击在线用户中的用户聊天,在发送消息的时候,需要将ConnectionId一并传入到服务端。
- 服务端根据传入的消息内容和ConnectionId调用Clients.Client(connnection).sendMessage方法来进行转发到对应的客户端。
[HubName("Chat")] public class ChatHub : Hub { // 静态属性,在线用户列表 public static List<UserInfo> OnlineUsers = new List<UserInfo>(); //登录 public void Login(string userId,string userName) { //获取客户端的ConnectionId var connnectId = Context.ConnectionId; OnlineUsers.Add(new UserInfo { ConnectionId = connnectId, UserId = userId, UserName = userName }); // 所有客户端同步在线用户 Clients.All.loadUser(OnlineUsers); } /// <summary> /// 发送私聊 /// </summary> /// <param name="toUserId">接收方用户连接ID</param> /// <param name="message">内容</param> public void SendPrivateMessage(string toUserId, string message) { var fromUserId = Context.ConnectionId; var toUser = OnlineUsers.FirstOrDefault(x => x.ConnectionId == toUserId); var fromUser = OnlineUsers.FirstOrDefault(x => x.ConnectionId == fromUserId); if (toUser != null && fromUser != null) { // 调用指定用户的客户端方法 Clients.Client(toUserId).receivePrivateMessage(fromUser.UserName, message); } else { //表示对方不在线 Clients.Caller.absentSubscriber(); } } /// <summary> /// 断线时调用 /// </summary> /// <param name="stopCalled"></param> /// <returns></returns> public override Task OnDisconnected(bool stopCalled) { var user = OnlineUsers.FirstOrDefault(u => u.ConnectionId == Context.ConnectionId); // 判断用户是否存在,存在则删除 if (user == null) return base.OnDisconnected(stopCalled); Clients.All.onUserDisconnected(user.ConnectionId, user.UserName); //调用客户端用户离线通知 // 删除用户 OnlineUsers.Remove(user); return base.OnDisconnected(stopCalled); } } //客户端代码: <h2>聊天系统</h2> <div class="container"> @using (Html.BeginForm("login", "Chat", FormMethod.Post, new { @class = "form-inline" })) { <label>用户Id:</label> @Html.TextBox("userId", "", new { @class = "form-control" }) <label>用户名:</label> @Html.TextBox("userName", "", new { @class = "form-control" }) <input type="button" id="btnLogin" value="登录" class="btn btn-default" /> } </div> <hr /> <div class="container"> <div class="col-md-3"> <div class="panel panel-default"> <div class="panel-heading"> 在线用户 </div> <div class="panel-body"> <ul id="userList"> </ul> </div> </div> </div> <div class="col-md-8"> <div class="panel panel-default"> <div class="panel-heading"> 聊天内容 </div> <div class="panel-body"> <ul id="msgList" > </ul> </div> <div class="panel-footer"> <label>消息To:</label> <label id="toUser"></label> @Html.TextBox("msg", "", new { @class = "form-control form-inline" }) <input type="button" id="btnSend" value="发送" class="btn btn-default" /> </div> </div> </div> </div> @section scripts{ <script src="~/Scripts/jquery.signalR-2.2.2.min.js"></script> <script src="~/signalr/hubs"></script> <script> //用户点击(选择用户) function selectUser(li) { var connectionId = $(li).attr("cid"); $('#toUser').text(connectionId); } $(function () { var chat = $.connection.Chat; //刷新在线列表 chat.client.loadUser = function (allUsers) { $('#userList').html(""); for (var i = 0; i < allUsers.length; i++) { var li = $('<li cid="' + allUsers[i].ConnectionId+'" onclick="selectUser(this)">' + allUsers[i].UserId + ':' + allUsers[i].UserName + '</li> '); $('#userList').append(li); } } //接收消息 chat.client.receivePrivateMessage = function (from, msg) { var li = $("<li>来自:" + from + "<br/>" + msg + "</li>"); $("#msgList").append(li); } $.connection.hub.start().done(function () { console.log("连接完成"); //登录 $('#btnLogin').click(function () { chat.server.login($("#userId").val(), $('#userName').val()) }) $('#btnSend').click(function () { chat.server.sendPrivateMessage($('#toUser').text(), $('#msg').val()) }) }); }) </script>