>  기사  >  백엔드 개발  >  Asp.net SignalR 적용 및 그룹 채팅 기능 구현에 대한 자세한 설명

Asp.net SignalR 적용 및 그룹 채팅 기능 구현에 대한 자세한 설명

Y2J
Y2J원래의
2017-04-27 15:58:451927검색

이 글은 주로 Asp.net SignalR 애플리케이션을 공유하고 그룹 채팅 기능을 구현합니다. 이는 특정 참고 가치가 있습니다. 관심 있는 친구는 이를 참조할 수 있습니다.

ASP.NET SignalR은 에서 제공하는 ASP A 라이브러리용입니다. NET 개발자는 개발자가 애플리케이션에 실시간 웹 기능을 추가하는 프로세스를 단순화합니다. 실시간 웹 기능은 클라이언트가 새 데이터를 요청할 때까지 서버가 기다리지 않고 서버 코드가 연결된 클라이언트에 콘텐츠가 제공되는 즉시 콘텐츠를 푸시할 수 있는 기능입니다. (공식 소개 중에서.)

SignalR 공식 홈페이지

-1. 이 글을 쓴 이유

전 글에서 B/S(웹 ) 실시간 통신 솔루션 계획에는 SignalR에 대한 자세한 소개가 없으므로 별도의 글에서 SignalR 소개에 중점을 두고 있습니다.

0. 먼저 최종 구현을 살펴보겠습니다

github.com/Emrys5/SignalRGroupChatDemo

1. 준비 작업

1.1 먼저 NuGet에서 SignalR 패키지를 다운로드합니다.

1.2. Owin 및 SignalR 구성

1.2.1. 시작 클래스, SignalR

public class Startup
 {
 public void Configuration(IAppBuilder app)
 {
  app.MapSignalR();
 }
 }

를 등록한 다음 web.config에서 시작 클래스를 구성하고 구성에

006f9f9605e1532bc638ccc3ebd99796 appSettings node ="SignalRChat.App_Start.Startup"/>

1.2.2. 페이지에 SignalR js 소개

1. SignalR 프런트 엔드는 jQuery를 기반으로 합니다. , 페이지에 jQuery를 도입해야 합니다.

2. SignalR의 js를 소개합니다.

3. 가장 중요한 허브 js를 소개합니다. 이 js는 실제로 존재하지 않습니다. SignalR은 클라이언트 호출에 대한 모든 메서드를 반영하여 허브 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에서 SendMsg를 호출할 수 있습니다.

[HubName("simpleHub")]
 public class SimpleHub : Hub
 { 
 public void SendMsg(string msg)
 {
 }
 }

이렇게 하면 기본적으로 사전 준비 작업은 완료되었으며, 구체적인 작업은 다음과 같습니다.

2. 원리와 간단한 프로그래밍

사실 원리가 이해하기 쉽다면 매우 간단합니다. 왜냐하면 http는 stateless이기 때문입니다. 각 요청은 서버와의 연결이 끊어집니다. 즉, 클라이언트가 서버를 쉽게 찾을 수 있지만 서버가 클라이언트에 메시지를 보내는 것이 더 번거로울 것입니다. 이해가 되지 않는 경우 이전 기사를 참조하세요. B/S(웹) 실시간 커뮤니케이션 솔루션입니다.

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 클래스에서 호출되는 메소드를 호출할 수 있습니다. 이렇게 하면 클라이언트에서 서버로 메시지를 보내는 것이 매우 간단해집니다.

링크 ID, 쿠키 등 Context에서 원하는 것을 얻을 수도 있습니다.

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의 중요한 기능인 클라이언트에 메시지를 보내는 방법을 보여줍니다. 여기서 해결해야 할 두 가지 문제가 있습니다.

질문 1. 연결된 모든 클라이언트에게 보내는 메시지는 다음과 같습니다. 단일 클라이언트 또는 클라이언트 그룹인 경우 어떻게 보내야 합니까?

질문 2: 클라이언트에 메시지를 보내기 위해 msg를 호출할 때 메시지를 받은 후 피드백을 주고 클라이언트에 메시지를 보냅니다. 이는 서버가 적극적으로 수행하지 않는 것과 매우 유사합니다. 메시지를 보내려면 클라이언트에게 메시지를 보내십시오.

해결책:

문제 1. 클라이언트는 기능 그룹이나 클라이언트에게 메시지를 보낼 수 있습니다.

// 所有人
Clients.All.msg("发送给客户端的消息"); 
// 特定 cooectionId
Clients.Client("connectionId").msg("发送给客户端的消息");
// 特定 group
Clients.Group("groupName").msg("发送给客户端的消息");

다음은 더 일반적으로 사용되는 세 가지입니다. 물론 AllExcept, Clients 등 더 많은 것들이 있습니다.

Others, OthersInGroup, OthersInGroups 등도 SignalR2.0에 추가되었습니다.

질문 2. 메시지를 보내야 하는 곳에서 클라이언트를 가져오기 위해 GlobalHost.ConnectionManager.GetHubContext6ee85620bd93624829d03c8c5f720a50().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, 1);

  // 向客户端发送在线人员
  Clients.All.publshUser(_onlineUser.Select(i => i.Key));

  // 向客户端发送加入聊天消息
  Clients.All.publshMsg(FormatMsg("系统消息", UserName + "加入聊天"));
  }
  else
  {
  // 如果是已经存在的用户,则把在线链接的个数+1
  _onlineUser[UserName] = _onlineUser[UserName] + 1;
  }

  // 加入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] - 1;

  // 判断是否断开了所有的链接
  if (_onlineUser[UserName] == 0)
  {
  // 移除在线人员
  _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 == "0")
  {
  // 发送给所有用户消息
  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=&#39;p&#39;>" + data.Name + ":</span>" + data.Msg + " <span class=&#39;time&#39;>" + data.Time + "</span></li>")
   $("#msg").parents("p")[0].scrollTop = $("#msg").parents("p")[0].scrollHeight;
  },

  // 接收在线人员,然后加入Select,以供单独聊天选中
  publshUser: function (data) {
   $("#count").text(data.length);
   $("#users").empty();
   $("#users").append(&#39;<option value="0">所有人</option>&#39;);
   for (var i = 0; i < data.length; i++) {
   $("#users").append(&#39;<option value="&#39; + data[i] + &#39;">&#39; + data[i] + &#39;</option>&#39;)
   }

  }
  });

  // 发送消息按钮
  $("#btn-send").click(function () {
  var msg = $("#txt-msg").val();
  if (!msg) {
   alert(&#39;请输入内容!&#39;); return false;
  }
  $("#txt-msg").val(&#39;&#39;);

  // 主动发送消息,传入发送给谁,和发送的内容。
  ticker.server.sendMsg($("#users").val(), msg);
  });

 });
 </script>

html代码

<h2>
 群聊系统(<span id="count">1</span>人在线):@ViewBag.UserName
</h2>


<p style="overflow:auto;height:300px">
 <ul id="msg"></ul>
</p>

<select id="users" class="form-control" style="max-width:150px;">
 <option value="0">所有人</option>
</select>

<input type="text" onkeydown=&#39;if (event.keyCode == 13) { $("#btn-send").click() }&#39; 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.com/Emrys5/SignalRGroupChatDemo

위 내용은 Asp.net SignalR 적용 및 그룹 채팅 기능 구현에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.