Asp.net SignalR 应用并实现群聊功能 开源代码
ASP.NET SignalR 是为 ASP.NET 开发人员提供的一个库,可以简化开发人员将实时 Web 功能添加到应用程序的过程。实时 Web 功能是指这样一种功能:当所连接的客户端变得可用时服务器代码可以立即向其推送内容,而不是让服务器等待客户端请求新的数据。(来自官方介绍。)
-1、写这篇的原因
在上篇文章B/S(Web)实时通讯解决方案中,并没有详情介绍SignalR,所以另起一篇专门介绍SignalR,本文的侧重点是Hub功能。
0、先看最终实现效果
github:https://github.com/Emrys5/SignalRGroupChatDemo
1、准备工作
1.1、在NuGet上首先下载SignalR的包。
1.2、配置Owin与SignalR
1.2.1、新建Startup类,注册SignalR
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
然后在web.config配置Startup类,在configuration=>appSettings节点中添加
<add key="owin:AppStartup" value="SignalRChat.App_Start.Startup"/>
1.2.2、在页面引入SignalR的js
1、由于SignalR前端是基于jQuery的,所以页面需引入jQuery。
2、引入SignalR的js 。
3、引入最重要的hubs js,这个js其实并不存在,SignalR会反射获取所有供客户端调用的方法放入hubs js中。
<script src="~/Scripts/jquery-1.10.2.js"></script>
<script src="~/Scripts/jquery.signalR-2.2.1.min.js"></script>
<script src="~/signalr/hubs"></script>
1.2.3、新建GroupChatHub类,并继承Hub抽象类
在hub类中的方法就是提供给客户端调用的js方法。
在js中就可以用signalr调用SendMsg。
[HubName("simpleHub")]
public class SimpleHub : Hub
{
public void SendMsg(string msg)
{ } }
这样基本上前期准备工作就做完了,后面就是具体的操作。
2、原理与简单的编程
其实原理如果简单点理解就很简单,因为http是无状态的,所以每次请求以后都会与服务器断开链接,那就是说客户端可以很容易找到服务器,但是服务器如果想给你客户端发送消息就比较麻烦,如果不明白的可以参考上一篇文章 B/S(Web)实时通讯解决方案。
SignalR就很好的解决了这个问题,也就说实现了实现了浏览器与服务器的全双工通信。
2.1、客户端至服务端(B=>S)
客户端代码
<script type="text/javascript">
var ticker = $.connection.simpleHub;
$.connection.hub.start(); $("#btn").click(function () { // 链接完成以后,可以发送消息至服务端
ticker.server.sendMsg("需要发送的消息");
}); </script>
服务端代码
[HubName("simpleHub")]
public class SimpleHub : Hub
{
public void SendMsg(string msg)
{
// 获取链接id
var connectionId = Context.ConnectionId;
// 获取cookie
var cookie = Context.RequestCookies; } }
其中SimpleHub就是我们定义的继承Hub类SimpleHub,然后我们可以用特性HubName进行重命名。
然后开始链接。
在链接完成以后,我们就可以调用在SimpleHub类中调用的方法。这就就很简单的实现了客户端至服务端发送消息。
我们还可以在Context中获取我们想要的东西,比如链接id,cookie等。
2.2、服务端至客户端(S=>B)
服务端代码
[HubName("simpleHub")]
public class SimpleHub : Hub
{
public void SendMsg(string msg)
{
Clients.All.msg("发送给客户端的消息");
} }
客户端代码
<script type="text/javascript"> var ticker = $.connection.groupChatHub;
$.connection.hub.start(); ticker.client.msg = function (data) {
console.log(data);
}
</script>
这里演示了怎么发送消息至客户端,也是SignalR比较重要的功能,这里有两个问题需要解决。
问题一、这里是发送消息给所有连着的客户端,如果是单个客户端或者是一批客户端应该怎么发送。
问题二、我们在调用msg给个客户端发送消息时是在接收消息以后做的反馈,然后发送消息给客户端,这样就很类似ajax了,服务端并没有主动给客户端发送消息。
解决:
问题一、Clients可以给特性的一群或者一个客户端发送消息
// 所有人
Clients.All.msg("发送给客户端的消息"); // 特定 cooectionId
Clients.Client("connectionId").msg("发送给客户端的消息"); // 特定 group
Clients.Group("groupName").msg("发送给客户端的消息");
这是比较常用的三个,当然还有很多,比如AllExcept,Clients。
在SignalR2.0中还添加了Others,OthersInGroup,OthersInGroups等等。
问题二、我们可以在需要发送消息的地方调用GlobalHost.ConnectionManager.GetHubContext<SimpleHub>().Clients中获取Clients。获取Clients并发送消息我们最好写成单例模式,因为这种需求很符合单例,群聊中有详细的代码。
3、SignalR实现群聊
以上的介绍和代码已经可以实现b=>s和s=>b了,那实现群聊和单独聊天就比较简单了。
由于功能比较简单,所有我把用户名存到了cookie里,也就说第一次进来时需要设置cookie。
还有就是在hub中要实现OnConnected、OnDisconnected和OnReconnected,然后在方法中设置用户和connectionid和统计在线用户,以便聊天使用。
hub代码
/// <summary>
/// SignalR Hub 群聊类
/// </summary>
[HubName("groupChatHub")] // 标记名称供js调用
public class GroupChatHub : Hub
{
/// <summary>
/// 用户名
/// </summary>
private string UserName
{
get
{
var userName = Context.RequestCookies["USERNAME"];
return userName == null ? "" : HttpUtility.UrlDecode(userName.Value);
}
} /// <summary>
/// 在线用户
/// </summary>
private static Dictionary<string, int> _onlineUser = new Dictionary<string, int>(); /// <summary>
/// 开始连接
/// </summary>
/// <returns></returns>
public override Task OnConnected()
{
Connected();
return base.OnConnected();
} /// <summary>
/// 重新链接
/// </summary>
/// <returns></returns>
public override Task OnReconnected()
{
Connected();
return base.OnReconnected();
} private void Connected()
{
// 处理在线人员
if (!_onlineUser.ContainsKey(UserName)) // 如果名称不存在,则是新用户
{ // 加入在线人员
_onlineUser.Add(UserName, ); // 向客户端发送在线人员
Clients.All.publshUser(_onlineUser.Select(i => i.Key)); // 向客户端发送加入聊天消息
Clients.All.publshMsg(FormatMsg("系统消息", UserName + "加入聊天"));
}
else
{
// 如果是已经存在的用户,则把在线链接的个数+1
_onlineUser[UserName] = _onlineUser[UserName] + ;
} // 加入Hub Group,为了发送单独消息
Groups.Add(Context.ConnectionId, "GROUP-" + UserName);
} /// <summary>
/// 结束连接
/// </summary>
/// <param name="stopCalled"></param>
/// <returns></returns>
public override Task OnDisconnected(bool stopCalled)
{
// 人员链接数-1
_onlineUser[UserName] = _onlineUser[UserName] - ; // 判断是否断开了所有的链接
if (_onlineUser[UserName] == )
{
// 移除在线人员
_onlineUser.Remove(UserName); // 向客户端发送在线人员
Clients.All.publshUser(_onlineUser.Select(i => i.Key)); // 向客户端发送退出聊天消息
Clients.All.publshMsg(FormatMsg("系统消息", UserName + "退出聊天"));
} // 移除Hub Group
Groups.Remove(Context.ConnectionId, "GROUP-" + UserName);
return base.OnDisconnected(stopCalled);
} /// <summary>
/// 发送消息,供客户端调用
/// </summary>
/// <param name="user">用户名,如果为0,则是发送给所有人</param>
/// <param name="msg">消息</param>
public void SendMsg(string user, string msg)
{
if (user == "")
{
// 发送给所有用户消息
Clients.All.publshMsg(FormatMsg(UserName, msg));
}
else
{
//// 发送给自己消息
//Clients.Group("GROUP-" + UserName).publshMsg(FormatMsg(UserName, msg)); //// 发送给选择的人员
//Clients.Group("GROUP-" + user).publshMsg(FormatMsg(UserName, msg)); // 发送给自己消息
Clients.Groups(new List<string> { "GROUP-" + UserName, "GROUP-" + user }).publshMsg(FormatMsg(UserName, msg)); }
} /// <summary>
/// 格式化发送的消息
/// </summary>
/// <param name="name"></param>
/// <param name="msg"></param>
/// <returns></returns>
private dynamic FormatMsg(string name, string msg)
{
return new { Name = name, Msg = HttpUtility.HtmlEncode(msg), Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") };
}
}
js代码
<script type="text/javascript">
$(function () { // 链接hub
var ticker = $.connection.groupChatHub;
$.connection.hub.start(); // 接收服务端发送的消息
$.extend(ticker.client, { // 接收聊天消息
publshMsg: function (data) {
$("#msg").append("<li><span class='p'>" + data.Name + ":</span>" + data.Msg + " <span class='time'>" + data.Time + "</span></li>")
$("#msg").parents("div")[].scrollTop = $("#msg").parents("div")[].scrollHeight;
}, // 接收在线人员,然后加入Select,以供单独聊天选中
publshUser: function (data) {
$("#count").text(data.length);
$("#users").empty();
$("#users").append('<option value="0">所有人</option>');
for (var i = ; i < data.length; i++) {
$("#users").append('<option value="' + data[i] + '">' + data[i] + '</option>')
} }
}); // 发送消息按钮
$("#btn-send").click(function () {
var msg = $("#txt-msg").val();
if (!msg) {
alert('请输入内容!'); return false;
}
$("#txt-msg").val(''); // 主动发送消息,传入发送给谁,和发送的内容。
ticker.server.sendMsg($("#users").val(), msg);
}); });
</script>
html代码
<h2>
群聊系统(<span id="count"></span>人在线):@ViewBag.UserName
</h2> <div style="overflow:auto;height:300px">
<ul id="msg"></ul>
</div> <select id="users" class="form-control" style="max-width:150px;">
<option value="">所有人</option>
</select> <input type="text" onkeydown='if (event.keyCode == 13) { $("#btn-send").click() }' class="form-control" id="txt-msg" placeholder="内容" style="max-width:400px;" />
<br />
<button type="button" id="btn-send">发送</button>
这样就消息了群聊和发送给特定的人聊天功能。
3.1、封装主动发送消息的单例
/// <summary>
/// 主动发送给用户消息,单例模式
/// </summary>
public class GroupChat
{
/// <summary>
/// Clients,用来主动发送消息
/// </summary>
private IHubConnectionContext<dynamic> Clients { get; set; } private readonly static GroupChat _instance = new GroupChat(GlobalHost.ConnectionManager.GetHubContext<GroupChatHub>().Clients); private GroupChat(IHubConnectionContext<dynamic> clients)
{
Clients = clients;
} public static GroupChat Instance
{
get
{
return _instance;
}
} /// <summary>
/// 主动给所有人发送消息,系统直接调用
/// </summary>
/// <param name="msg"></param>
public void SendSystemMsg(string msg)
{
Clients.All.publshMsg(new { Name = "系统消息", Msg = msg, Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") });
}
}
如果需要发送消息,直接调用SendSystemMsg即可。
GroupChat.Instance.SendSystemMsg("消息");
4、结语
啥也不说了直接源码
github:https://github.com/Emrys5/SignalRGroupChatDemo
最后望对各位有所帮助,本文原创,欢迎拍砖和推荐。
Asp.net SignalR 应用并实现群聊功能 开源代码的更多相关文章
- java项目-----客户端与客户端通信--实现群聊功能的代码
这是这个网络聊天室项目的原理图: 很简单,首先ABCD是4个客户端,当A发送信息给服务器,服务器实现以广播的形式把信息全发给每个人---群发群聊 客户端代码: package com.aa; impo ...
- Java-->实现群聊功能(C/S模式--TCP协议)
--> Java 对TCP协议的支持: --> java.net包中定义了两个类ServerSocket 和Socket ,分别用来实现双向连接的server 端和client 端. -- ...
- day04-1群聊功能
多用户即时通讯系统04 4.编码实现03 4.5功能实现-群聊功能实现 4.5.1思路分析 群聊的实现思路和私聊的实现非常类似. 不同的是:私聊时,服务端接收到消息后,只需要找出接收方的socket并 ...
- ASP.NET SignalR 与LayIM配合,轻松实现网站客服聊天室(四) 添加表情、群聊功能
休息了两天,还是决定把这个尾巴给收了.本篇是最后一篇,也算是草草收尾吧.今天要加上表情功能和群聊.基本上就差不多了,其他功能,读者可以自行扩展或者优化.至于我写的代码方面,自己也没去重构.好的,我们开 ...
- netty无缝切换rabbitmq、activemq、rocketmq实现聊天室单聊、群聊功能
netty的pipeline处理链上的handler:需要IdleStateHandler心跳检测channel是否有效,以及处理登录认证的UserAuthHandler和消息处理MessageHan ...
- Websocket 群聊功能
websocket 群聊 前提关闭防火墙 写入代码 from flask import Flask,request,render_template from geventwebsocket.handl ...
- netty实现群聊功能
[概述] 实现一个网络群聊工具.参与聊天的客户端消息是通过服务端进行广播的. 主要由两块组成:聊天服务器端(ChatServer)和聊天客户端(ChatClient). 聊天服务器(ChatServe ...
- 基于koa模块和socket.io模块搭建的node服务器实现通过jwt 验证来渲染列表、私聊、群聊功能
1. 具体代码在需要的下载 https://gitee.com/zyqwasd/socket 效果: 2. package.json文件 1. 下载基本的模块 修改了start 脚本 nodemo ...
- Java网络编程Demo,使用TCP 实现简单群聊功能GroupchatSimple,多个客户端输入消息,显示在服务端的控制台
效果: 服务端 客户端 实现代码: 服务端 import java.io.IOException; import java.net.ServerSocket; import java.net.Sock ...
随机推荐
- 【吐血整理】svn命令行,Subversion的正确使用姿势~
一.写在前面 前面一直博主一直用svn的桌面版本,但看项目经理一直都用的命令行方式,不为性能,还能直接装逼呀!在这里先感谢赵哥,也把它分享给感兴趣的你们~ 二.直接上干货 1. svn checkou ...
- 开源中文分词工具探析(四):THULAC
THULAC是一款相当不错的中文分词工具,准确率高.分词速度蛮快的:并且在工程上做了很多优化,比如:用DAT存储训练特征(压缩训练模型),加入了标点符号的特征(提高分词准确率)等. 1. 前言 THU ...
- [翻译]现代java开发指南 第一部分
现代java开发指南 第一部分 第一部分:Java已不是你父亲那一代的样子 第一部分,第二部分 =================== 与历史上任何其他的语言相比,这里要排除c语言和cobol语言,现 ...
- webservice基本功能介绍
WebService, 能使得运行在不同机器上的不同应用无须借助附加的.专门的第三方软件或硬件, 就可相互交换数据或集成.依据WebService规范实施的应用之间, 无论它们所使用的语言. 平台或内 ...
- USB重定向
第一期中,我们一起简要的看了下传统PC和桌面云下USB重定向和USB设备重定向方式的差异,了解了桌面云下外设兼容性问题来源的根源-USB设备本身驱动不规范/不支持, 或者虚拟机驱动实现上与USB设备对 ...
- 结合prototype和xmlhttprequest封装ajax请求
由于拖延症的严重以及年前准备年会(借口*^__^*) 导致这个小的的思考 现在才算完成 再怎么说也算是上班以来带我的前辈第一次这么正式的给我出题 不管是出于尊重还是自我要求我都决定把它简要的记下来 ...
- Java中byte与16进制字符串的互换原理
我们都知道Java中的byte是由8个bit组成的,而16进制即16中状态,它是由4个bit来表示的,因为24=16.所以我们可以把一个byte转换成两个用16进制字符,即把高4位和低4位转换成相应的 ...
- sed 删除换行符
sed 删除换行符 sed ':label;N;s/\n/:/;b label' filename sed ':label;N;s/\n/:/;t label' filename 上面的两条命令可以实 ...
- JSON的服务器开发之路
JSON的服务器开发之路 不知道需要哪儿些包... /dcywpt/WebRoot/WEB-INF/lib/commons-collections-3.2.jar /dcywpt/WebRoot/WE ...
- CSS限制字数,超出部份显示点点点...
最近项目中需要用CSS实现限制字数,超出部份显示点点点...,只需要一下代码即可: width:400px;/*要显示文字的宽度*/ text-overflow :ellipsis; /*让截断的文字 ...