1、简介:Signal 是微软支持的一个运行在 Dot NET 平台上的 html websocket 框架。它出现的主要目的是实现服务器主动推送(Push)消息到客户端页面,这样客户端就不必重新发送请求或使用轮询技术来获取消息。
可访问其官方网站:https://github.com/SignalR/ 获取更多资讯。
2、SignalR 的实现机制与 .NET WCF 或 Remoting 是相似的,都是使用远程代理来实现。在具体使用上,有两种不同目的的接口:PersistentConnection 和 Hubs,其中 PersistentConnection 是实现了长时间的 Javascript 轮询(类似于 Comet),Hub 是用来解决实时信息交换问题,它是利用 Javascript 动态载入执行方法实现的。SignalR 将整个连接,信息交换过程封装得非常漂亮,客户端与服务器端全部使用 JSON 来交换数据。
下面就 Hubs 接口的使用来讲讲整个流程:
(1),在服务器端定义对应的 hub class;
(2),在客户端定义 hub class 所对应的 proxy 类;
(3),在客户端与服务器端建立连接(connection);
(4),然后客户端就可以调用 proxy 对象的方法来调用服务器端的方法,也就是发送 request 给服务器端;
(5),服务器端接收到 request 之后,可以针对某个/组客户端或所有客户端(广播)发送消息。
以上这些都是关注大神们了解的。
(1)、在SignalR通讯 项目下安装 SignalR(找到程序包管理器控制台,输入:Install-Package Microsoft.AspNet.SignalR)
安装成功后系统会自动生成一个Scripts文件夹,里面存放对应的js文件,如图
(1)、新建一个SignalR集线器ServerHub,如图
并编写以下代码
- public class ServerHub : Hub
- {
- private static readonly char[] str =
- {
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
- 'w', 'x', 'y', 'z',
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
- 'W', 'X', 'Y', 'Z'
- };
- /// <summary>
- /// 消息发送接口
- /// </summary>
- /// <param name="message"></param>
- public void SendMsg(string message)
- {
- var name = GenerateUserName(4);
- // 调用所有客户端的sendMessage方法
- Clients.All.sendMessage(name, message);
- }
- /// <summary>
- /// 产生随机用户
- /// </summary>
- /// <param name="length">用户名长度</param>
- /// <returns></returns>
- public static string GenerateUserName(int length)
- {
- var newRandom = new StringBuilder(62);
- var rd = new Random();
- for (var i = 0; i < length; i++)
- {
- newRandom.Append(str[rd.Next(62)]);
- }
- return newRandom.ToString();
- }
(2)、创建一个Startup类,(如果创建项目是有这个类。就不用添加了)添加代码如下
- public void Configuration(IAppBuilder app)
- {
- // 配置集线器
- app.MapSignalR();
- }
(3)、添加Home控制器及视图Index(此步骤不截图)
(4)、添加Index视图代码 如下
- @{
- Layout = "~/Views/Shared/_Layout.cshtml";
- ViewBag.Title = "聊天窗口";
- }
- <h2>Index</h2>
- <div class="container">
- <input type="text" id="message" />
- <input type="button" id="sendmessage" value="Send" />
- <input type="hidden" id="displayname" />
- <ul id="discussion"></ul>
- </div>
- @section scripts
- {
- <script src="~/Scripts/jquery-1.6.4.min.js"></script>
- <!--引用SignalR库. -->
- <script src="~/Scripts/jquery.signalR-2.2.2.min.js"></script>
- <!--引用自动生成的SignalR 集线器(Hub)脚本.在运行的时候在浏览器的Source下可看到 -->
- <script src="~/signalr/hubs"></script>
- <script>
- $(function () {
- // 引用集线器代理
- var chat = $.connection.serverHub;
- // 定义服务器端调用的客户端sendMessage来显示新消息
- chat.client.sendMessage = function (name, message) {
- // 向页面添加消息
- $('#discussion').append('<li><strong>' + htmlEncode(name)
- + '</strong>: ' + htmlEncode(message) + '</li>');
- };
- // 设置焦点到输入框
- $('#message').focus();
- // 开始连接服务器
- $.connection.hub.start().done(function () {
- $('#sendmessage').click(function () {
- // 调用服务器端集线器的SendMsg方法
- chat.server.sendMsg($('#message').val());
- // 清空输入框信息并获取焦点
- $('#message').val('').focus();
- });
- });
- });
- // 为显示的消息进行Html编码
- function htmlEncode(value) {
- var encodedValue = $('<div />').text(value).html();
- return encodedValue;
- }
- </script>
- }
(1)、如果出现如下错误,请删除红框里的代码
成功之后的结果,如图
你以为完了嘛?还没有,别急往下看
(1)、在layer官网下载layer前端js和ui(在我上一篇的文章中有下载地址,或者直接百度搜索layer),放到你的项目中,在这里我们就不直接说页面代码的编写部分,直接看下我们的效果图,如下
(2)、在完成聊天之前。我们还需要做什么,对做登录,在这里自动生成的用户已经不能满足我们接下来的需求了(登录教程跳过)直接看登录成功过后的界面
这样看起来就美观多了,其实在线所有人聊天的功能,就是刚刚我们实现那个功能是一样的,没有任何的变化(只是美观了下),看看聊天结果吧
(1)、首先我们的建一个群聊的实体(UserGroup)和房间实体(ChatRoom),如下图
(2)、在我们建好的ServerHub类里编写如下代码(具体实现看源码)
- public static ChatContext DbContext = new ChatContext();
- // 重写Hub连接断开的事件 (断线时调用)
- public override Task OnDisconnected(bool stopCalled)
- {
- // 查询用户
- var user = DbContext.Users.FirstOrDefault(u => u.UserId == Context.ConnectionId);
- if (user != null)
- {
- // 删除用户
- DbContext.Users.Remove(user);
- // 从房间中移除用户
- foreach (var item in user.Rooms)
- {
- RemoveUserFromRoom(item.RoomName);
- }
- }
- return base.OnDisconnected(stopCalled);
- }
- // 为所有用户更新房间列表
- public void UpdateRoomList()
- {
- var itme = DbContext.Rooms.Select(p => new { p.RoomName });
- var jsondata = JsonHelper.ToJsonString(itme.ToList());
- Clients.All.getRoomlist(jsondata);
- }
- /// <summary>
- /// 加入聊天室
- /// </summary>
- public void JoinRoom(string roomName)
- {
- // 查询聊天室
- var room = DbContext.Rooms.Find(p => p.RoomName == roomName);
- // 存在则加入
- if (room == null) return;
- // 查找房间中是否存在此用户
- var isExistUser = room.Users.FirstOrDefault(u => u.UserId == Context.ConnectionId);
- // 不存在则加入
- if (isExistUser == null)
- {
- var user = DbContext.Users.Find(u => u.UserId == Context.ConnectionId);
- user.Rooms.Add(room);
- room.Users.Add(user);
- // 将客户端的连接ID加入到组里面
- Groups.Add(Context.ConnectionId, roomName);
- //调用此连接用户的本地JS(显示房间)
- Clients.Client(Context.ConnectionId).joinRoom(roomName);
- }
- else
- {
- Clients.Client(Context.ConnectionId).showMessage("请勿重复加入房间!");
- }
- }
- /// <summary>
- /// 创建聊天室
- /// </summary>
- /// <param name="roomName"></param>
- public void CreateRoom(string roomName)
- {
- var room = DbContext.Rooms.Find(a => a.RoomName == roomName);
- if (room == null)
- {
- var cr = new ChatRoom
- {
- RoomName = roomName
- };
- //将房间加入列表
- DbContext.Rooms.Add(cr);
- // 本人加入聊天室
- JoinRoom(roomName);
- UpdateRoomList();
- }
- else
- {
- Clients.Client(Context.ConnectionId).showMessage("房间名重复!");
- }
- }
- public void RemoveUserFromRoom(string roomName)
- {
- //查找房间是否存在
- var room = DbContext.Rooms.Find(a => a.RoomName == roomName);
- //存在则进入删除
- if (room == null)
- {
- Clients.Client(Context.ConnectionId).showMessage("房间名不存在!");
- return;
- }
- // 查找要删除的用户
- var user = room.Users.FirstOrDefault(a => a.UserId == Context.ConnectionId);
- // 移除此用户
- room.Users.Remove(user);
- //如果房间人数为0,则删除房间
- if (room.Users.Count <= 0)
- {
- DbContext.Rooms.Remove(room);
- }
- Groups.Remove(Context.ConnectionId, roomName);
- //提示客户端
- Clients.Client(Context.ConnectionId).removeRoom("退出成功!");
- }
- /// <summary>
- /// 给房间内所有的用户发送消息
- /// </summary>
- /// <param name="room">房间名</param>
- /// <param name="message">信息</param>
- public void SendMessage(string room, string message)
- {
- // 调用房间内所有客户端的sendMessage方法
- // 因为在加入房间的时候,已经将客户端的ConnectionId添加到Groups对象中了,所有可以根据房间名找到房间内的所有连接Id
- // 其实我们也可以自己实现Group方法,我们只需要用List记录所有加入房间的ConnectionId
- // 然后调用Clients.Clients(connectionIdList),参数为我们记录的连接Id数组。
- Clients.Group(room, new string[0]).sendMessage(room, message + " " + DateTime.Now);
- }
(3)、在Home控制器里创建GroupUser视图并添加如下代码
- @ {
- Layout = null;
- }
- < !DOCTYPE html >
- <html > <head > <meta name = "viewport"content = "width=device-width" / ><title > Index < /title>
- <script src="~/Scripts / jquery - 1.10.2.min.js "></script>
- <script src="~ / Scripts / jquery.signalR - 2.2.0.min.js "></script>
- <script src="~ / Scripts / layer / layer.js "></script>
- <!--这里要注意,这是虚拟目录,也就是你在OWIN Startup中注册的地址-->
- <script src=" / signalr / hubs "></script>
- <script type="text / javascript ">
- var chat;
- var roomcount = 0;
- $(function() {
- chat = $.connection.serverHub;
- chat.client.showMessage = function(message) {
- alert(message);
- };
- chat.client.sendMessage = function(roomname, message) {
- $("#" + roomname).find("ul ").each(function() {
- $(this).append('<li>' + message + '</li>');
- });
- };
- chat.client.removeRoom = function(data) {
- alert(data);
- };
- chat.client.joinRoom = function (roomname) {
- var html = '<div style="float: left;
- margin - left: 360px;
- border: double;
- height: 528px;
- width: 493px " id="' + roomname + '" roomname="' + roomname + '"><button onclick="RemoveRoom(this)">退出</button>\
- ' + roomname + '房间\
- 聊天记录如下:<ul>\
- </ul>\
- <textarea class="ChatCore_write " id="ChatCore_write " style="width: 400px "></textarea> <button onclick="SendMessage(this)">发送</button>\
- </div>';
- $("#RoomList ").append(html);
- };
- //注册查询房间列表的方法
- chat.client.getRoomlist = function(data) {
- if (data) {
- var jsondata = $.parseJSON(data);
- $("#roomlist ").html("");
- for (var i = 0; i < jsondata.length; i++) {
- var html = ' <li>房间名:' + jsondata[i].RoomName + '<button roomname="' + jsondata[i].RoomName + '" onclick="AddRoom(this)">加入</button></li>';
- $("#roomlist ").append(html);
- }
- }
- };
- // 获取用户名称。
- $('#username').html(prompt('请输入您的名称:', ''));
- $.connection.hub.start().done(function() {
- $('#CreatRoom').click(function() {
- chat.server.createRoom($("#Roomname ").val());
- });
- });
- });
- function SendMessage(btn) {
- var message = $(btn).prev().val();
- var room = $(btn).parent();
- var username = $("#username ").html();
- message = username + ": " + message;
- var roomname = $(room).attr("roomname ");
- chat.server.sendMessage(roomname, message);
- $(btn).prev().val('').focus();
- }
- function RemoveRoom(btn) {
- var room = $(btn).parent();
- var roomname = $(room).attr("roomname ");
- chat.server.removeUserFromRoom(roomname);
- }
- function AddRoom(roomname) {
- var data =$(roomname).attr("roomname ");
- chat.server.joinRoom(data);
- }
- </script>
- </head>
- <body>
- <div>
- <div>名称:<p id="username "></p></div>
- 输入房间名:
- <input type="text " value="聊天室1 " id="Roomname " />
- <button id="CreatRoom ">创建聊天室</button>
- </div>
- <div style="float: left;
- border: double ">
- <div>房间列表</div>
- <ul id="roomlist "></ul>
- </div>
- <div id="RoomList ">
- </div>
- </body>
- </html>"
(4)、做好以上步骤之后,主要的功能已经实现,那么接下来我们看下效果 如下
点击发送群聊之后出现如图所示
并创建自己的用户名
我们在创建自己的用户名之后,可以选择自己创建房间或者加入已有的房间,如下图
(1)、私聊我们在这里就不多说了。实现原理和群里差不多。都是找到对应的人员id就ok,直接上图看结果
源码请加qq群:460362190 里面有更多的开源项目哦,欢迎加入讨论
如果你还满意请点击关注和推荐,谢谢
来源: http://www.cnblogs.com/cyzf/p/7808798.html