1. Introduction
Dans l'article précédent, SignalR a été présenté en détail et son application dans Asp.net MVC et WPF a été brièvement présentée. Le dernier article de blog présentait la mise en œuvre de la messagerie de groupe. Cependant, SignalR est né pour le chat en temps réel, il lui manque donc naturellement le chat de bout en bout contrairement à QQ. Cet article de blog expliquera comment utiliser SignalR pour implémenter des fonctions similaires au chat QQ.
2. L'idée d'utiliser SignalR pour implémenter le chat de bout en bout
Avant d'introduire l'implémentation spécifique, j'ai d'abord présenté l'idée d'utiliser SignalR pour implémenter discussion de bout en bout. Je pense que vous avez vu du code comme Clients.All.sendMessage(name, message); dans l'article précédent, ce qui signifie appeler SendMessage de tous les clients. Le hub de SignalR permet une communication en temps réel entre les clients et les serveurs. Pour réaliser une conversation de bout en bout, vous ne pouvez naturellement pas envoyer de messages à tous les clients, mais vous ne pouvez envoyer des messages qu'à des clients spécifiques, sinon ce sera chaotique et il n'y aura pas de confidentialité. Alors, comment puis-je envoyer un message à un client spécifique ? Ce problème est la clé de notre implémentation de la fonction de chat de bout en bout.
En plus de l'attribut All, l'objet Clients que nous envoyons a également d'autres attributs. Vous pouvez appuyer sur F12 dans VS pour afficher tous les attributs ou méthodes de l'objet Clients. Les définitions spécifiques sont les suivantes :
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); // 参数中的用户 }
Dans SignalR, afin de marquer son unicité, SignalR lui attribuera un ConnnectionId afin que nous puissions trouver le client spécifique via le ConnnectionId. De cette façon, lorsque nous envoyons un message à un client, en plus de transmettre le message, nous devons également saisir le ConnectionId envoyé à l'autre partie, afin que le serveur puisse transmettre le message correspondant au client correspondant en fonction du ID de connexion entrant servi. Ceci termine la fonction de chat de bout en bout. De plus, si l'utilisateur n'est pas en ligne, le serveur peut enregistrer le message dans la base de données. Lorsque le client correspondant se connecte, il peut vérifier dans la base de données si le client a des messages à transmettre. Si tel est le cas, récupérez-le. données de la base de données, transmettez les données au client. (Cependant, la fonction de mise en cache des données côté serveur n'est pas implémentée dans cet article de blog. L'introduction ici est pour permettre à chacun de comprendre l'un des principes d'implémentation de QQ).
Trions maintenant les idées d'implémentation de la fonction de chat de bout en bout :
Lorsque le client se connecte, enregistrez le ConnectionId du client et ajoutez l'utilisateur à un tableau statique ces données. est destiné à enregistrer tous les utilisateurs en ligne.
Les utilisateurs peuvent cliquer sur le chat entre utilisateurs en ligne. Lors de l'envoi d'un message, le ConnectionId doit être transmis au serveur.
Le serveur appelle la méthode Clients.Client(connection).sendMessage en fonction du contenu du message entrant et de ConnectionId pour le transmettre au client correspondant.
3. Implémentez le code de base de la fonction de chat cool
Avec l'idée d'implémentation, il sera facile d'implémenter la fonction. Ensuite, jetons d'abord un coup d'œil. au hub ChatHub Code :
public class ChatHub : Hub { // 静态属性 public static List<UserInfo> OnlineUsers = new List<UserInfo>(); // 在线用户列表 /// <summary> /// 登录连线 /// </summary> /// <param name="userId">用户Id</param> /// <param name="userName">用户名</param> public void Connect(string userId, string userName) { var connnectId = Context.ConnectionId; if (OnlineUsers.Count(x => x.ConnectionId == connnectId) == 0) { if (OnlineUsers.Any(x => x.UserId == userId)) { var items = OnlineUsers.Where(x => x.UserId == userId).ToList(); foreach (var item in items) { Clients.AllExcept(connnectId).onUserDisconnected(item.ConnectionId, item.UserName); } OnlineUsers.RemoveAll(x => x.UserId == userId); } //添加在线人员 OnlineUsers.Add(new UserInfo { ConnectionId = connnectId, UserId = userId, UserName = userName, LastLoginTime = DateTime.Now }); } // 所有客户端同步在线用户 Clients.All.onConnected(connnectId, userName, 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) { // send to Clients.Client(toUserId).receivePrivateMessage(fromUserId, fromUser.UserName, message); // send to caller user // Clients.Caller.sendPrivateMessage(toUserId, 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); } }
Ce qui précède est l'implémentation principale du serveur. Examinons ensuite le code d'implémentation du client :
<script type="text/javascript"> var systemHub = $.connection.chatHub; / 连接IM服务器成功 // 主要是更新在线用户 systemHub.client.onConnected = function (id, userName, allUsers) { var node = chatCore.node, myf = node.list.eq(0), str = '', i = 0; myf.addClass('loading'); onlinenum = allUsers.length; if (onlinenum > 0) { str += '<li class="ChatCore_parentnode ChatCore_liston">' + '<h5><i></i><span class="ChatCore_parentname">在线用户</span><em class="ChatCore_nums">(' + onlinenum + ')</em></h5>' + '<ul id="ChatCore_friend_list" class="ChatCore_chatlist">'; for (; i < onlinenum; i++) { str += '<li id="userid-' + allUsers[i].UserID + '" data-id="' + allUsers[i].ConnectionId + '" class="ChatCore_childnode" type="one"><img src="/Content/Images/001.jpg?' + allUsers[i].UserID + '" class="ChatCore_oneface" alt="Asp.net utilise SignalR pour implémenter une fonction de chat de bout en bout intéressante" ><span class="ChatCore_onename">' + allUsers[i].UserName + '(' + ')</span><em class="ChatCore_time">' + allUsers[i].LoginTime + '</em></li>'; } str += '</ul></li>'; myf.html(str); } else { myf.html('<li class="ChatCore_errormsg">没有任何数据</li>'); } myf.removeClass('loading'); }; //消息传输 chatCore.transmit = function () { var node = chatCore.node, log = {}; node.sendbtn = $('#ChatCore_sendbtn'); node.imwrite = $('#ChatCore_write'); //发送 log.send = function () { var data = { content: node.imwrite.val(), id: chatCore.nowchat.id, sign_key: '', //密匙 _: +new Date }; if (data.content.replace(/\s/g, '') === '') { layer.tips('说点啥呗!', '#ChatCore_write', 2); node.imwrite.focus(); } else { //此处皆为模拟 var keys = chatCore.nowchat.type + chatCore.nowchat.id; //聊天模版 log.html = function (param, type) { return '<li class="' + (type === 'me' ? 'ChatCore_chateme' : '') + '">' + '<div class="ChatCore_chatuser">' + function () { if (type === 'me') { return '<span class="ChatCore_chattime">' + param.time + '</span>' + '<span class="ChatCore_chatname">' + param.name + '</span>' + '<img src="' + param.face + '" alt="Asp.net utilise SignalR pour implémenter une fonction de chat de bout en bout intéressante" >'; } else { return '<img src="' + param.face + '" alt="Asp.net utilise SignalR pour implémenter une fonction de chat de bout en bout intéressante" >' + '<span class="ChatCore_chatname">' + param.name + '</span>' + '<span class="ChatCore_chattime">' + param.time + '</span>'; } }() + '</div>' + '<div class="ChatCore_chatsay">' + param.content + '<em class="ChatCore_zero"></em></div>' + '</li>'; }; log.imarea = chatCore.chatbox.find('#ChatCore_area' + keys); log.imarea.append(log.html({ time: new Date().toLocaleString(), name: config.user.name, face: config.user.face, content: data.content }, 'me')); node.imwrite.val('').focus(); log.imarea.scrollTop(log.imarea[0].scrollHeight); // 调用服务端sendPrivateMessage方法来转发消息 systemHub.server.sendPrivateMessage(chatCore.nowchat.id, data.content); } }; node.sendbtn.on('click', log.send); node.imwrite.keyup(function (e) { if (e.keyCode === 13) { log.send(); } }); }; //用户离线 systemHub.client.onUserDisconnected = function (id, userName) { onlinenum = onlinenum - 1; $(".ChatCore_nums").html("(" + onlinenum + ")"); $("#ChatCore_friend_list li[data-id=" + id + "]").remove(); }; // 启动连接 $.connection.hub.start().done(function () { systemHub.server.connect(userid, username); // 调用服务端connect方法 }); </script>
Ce qui précède ne répertorie que certaines implémentations de code de base. De plus, afin d'obtenir des effets sympas, un plug-in Jquery est utilisé ici : layer Le site officiel est : http://layer.layui.com/. Ce plug-in est principalement utilisé pour obtenir les effets de boîtes contextuelles et de couches contextuelles. Pour obtenir des effets de chat sympas, vous devez écrire vous-même du code JS. Comme je ne connais pas très bien le front-end, ce JS. Le code des effets spéciaux est également basé sur la mise en œuvre sur Internet. Si vous souhaitez l'exécuter et voir l'effet, il est recommandé de télécharger le code source à la fin de l'article et de l'exécuter.
4. Effet final
Après avoir présenté les idées d'implémentation et le code d'implémentation, maintenant que nous avons atteint notre moment passionnant, c'est-à-dire voir si nos fonctions implémentées peuvent répondre aux besoins. De plus, en plus de répondre aux fonctions de chat de base, vous devez également voir si l'interface est suffisamment cool.
Plus Asp.net utilise SignalR pour implémenter une fonction de chat de bout en bout intéressante liée articles Veuillez faire attention au site Web chinois PHP !