门户网站建设的意义,问答网站建设,郑州app网站开发,旅游网站建设初衷主题列表#xff1a; COMET彗星#xff08;一#xff09;SERVER PUSH介绍 COMET彗星#xff08;二#xff09;基于SERVER PUSH的消息传输 引言#xff1a; 在上一篇随笔中#xff0c;对COMET使用的类和作用进行了简短的介绍#xff0c;从本篇随笔开始#xff0c;将从实…主题列表 COMET彗星一SERVER PUSH介绍 COMET彗星二基于SERVER PUSH的消息传输 引言 在上一篇随笔中对COMET使用的类和作用进行了简短的介绍从本篇随笔开始将从实体类开始对COMET的核心进行构建分析。 CORE框架 图1.1 COMET核心框架 CometMessage类 CometMessage类是COMET的通信载体对消息的主体进行抽象实际上这个类是最容易进行扩展的因为从设计上看它只是一个消息的容器。而诸如地理坐标业务数据等都可以通过这个类来进行直接扩充。 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.Serialization; namespace MethodWorx.AspNetComet.Core { /// summary /// CometMessage Class /// /// This is a CometMessage that has been sent to the client, the DataContract names have been /// shortened to remove any bytes we dont need from the message (ok, didnt save much, but we can do it!) /// /summary [DataContract(Namecm)] public class CometMessage { [DataMember(Namemid)] private long messageId; [DataMember(Namen)] private string name; [DataMember(Namec)] private object contents; /// summary /// Gets or Sets the MessageId, used to track which message the Client last received /// /summary public long MessageId { get { return this.messageId; } set { this.messageId value; } } /// summary /// Gets or Sets the Content of the Message /// /summary public object Contents { get { return this.contents; } set { this.contents value; } } /// summary /// Gets or Sets the error message if this is a failure /// /summary public string Name { get { return this.name; } set { this.name value; } } } } 类的设计简单明了这里有必要解释下使用System.Runtime.Serialization命名空间的意义。 “System.Runtime.Serialization 命名空间包含可用于将对象序列化和反序列化的类。序列化是将对象或对象图形转换为线性字节序列以存储或传输到另一个位置的过程。反序列化是接受存储的信息并利用它重新创建对象的过程。” 这是MSDN给我们的解释将对象转变为线性字节然后方便传输与调用。当然这个例子中的数据类型并不复杂但也包含了LONGOBJECTSTRING这样的数据类型。其中Contents成员为object对象这给我们留下了非常大的想像空间。图片复杂对象类型自定义对象类型…… CometClient类 CometClient类是对客户端信息的抽象类同时包含了两个关键属性ConnectionIdleSeconds和ConnectionTimeoutSeconds。由于考虑到不同客户端间传递属性仍然使用System.Runtime.Serialization来序列化信息。 关于JSON的应用这个框架其实也提供了相应支持。后面的随笔中我会介绍。 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.Serialization; namespace MethodWorx.AspNetComet.Core { /// summary /// CometClient Class /// /// This represents a logged in client within the COMET application. This marked as a DataContract becuase /// it can be seralized to the client using JSON /// /summary [DataContract] public class CometClient { [DataMember] private string privateToken; [DataMember] private string publicToken; [DataMember] private string displayName; [DataMember] private DateTime lastActivity; [DataMember] private int connectionIdleSeconds; [DataMember] private int connectionTimeoutSeconds; /// summary /// Gets or Sets the token used to identify the client to themselves /// /summary public string PrivateToken { get { return this.privateToken; } set { this.privateToken value; } } /// summary /// Gets or Sets the token used to identify the client to other clients /// /summary public string PublicToken { get { return this.publicToken; } set { this.publicToken value; } } /// summary /// Gets or Sets the display name of the client /// /summary public string DisplayName { get { return this.displayName; } set { this.displayName value; } } /// summary /// Gets or Sets the last activity of the client /// /summary public DateTime LastActivity { get { return this.lastActivity; } set { this.lastActivity value; } } /// summary /// Gets or Sets the ConnectionIdleSections property which is the number of seconds a connection will remain /// alive for without being connected to a client, after this time has expired the client will /// be removed from the state manager /// /summary public int ConnectionIdleSeconds { get { return this.connectionIdleSeconds; } set { this.connectionIdleSeconds value; } } /// summary /// Gets or Sets the ConnectionTimeOutSections property which is the number of seconds a connection will remain /// alive for whilst being connected to a client, but without receiving any messages. After a timeout has expired /// A client should restablish a connection to the server /// /summary public int ConnectionTimeoutSeconds { get { return this.connectionTimeoutSeconds; } set { this.connectionTimeoutSeconds value; } } } } ConnectionIdleSeconds用来设置连接线程当connection断线后后台Thread的存活时间。 ConnectionTimeoutSeconds客户端的超时时间当超过时间后客户端重新连接服务器。 ps:有这两个属性后基本上完成了客户端连接的控制超时重连接无连接时杀死后台线程。 ICometStateProvider接口 ICometStateProvider接口直接被CometStateMessager建立这样的好处是实例化CometStateMessager对象后CometStateMessager对象可以直接调用ICometStateProvider接口的实现实际上实现了Adapter的方式我们可以定制不同的InProcCometStateProvider类在下面会提到来定制自己的接口。 ICometStateProvider接口类提供了如下几个接口。 InitializeClient:提供ComentClient的初始化操作。 GetMessages:得到一个Messages的消息队列。 SendMessage:发送Message数据。 SendMessage:可以针对Client name来进行消息发布私人会话。 GetCometClient:返回一个Client。 KillIdleCometClient:杀掉一个无效的Client对象。 ps:当然这个接口是可以被拓展的而且实现起来非常简单。得到Client队列信息得到Client状态等等。甚至你可以想象一些更复杂的应用比如加入一个流媒体消息……。 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MethodWorx.AspNetComet.Core { /// summary /// This interface can be implemented to provide a custom state provider /// for the CometStateManager class. Typical examples may be using SqlServer /// to enable the operation over a server farm /// /summary public interface ICometStateProvider { /// summary /// Implementation of this method should store the cometClient instance in some sort /// of cache (eg Memory, Db etc..) /// /summary /// param namecometClient/param void InitializeClient(CometClient cometClient); /// summary /// Imeplementation of this method should return all the messages that are queued /// for a specific client, it is only interested in messages that have a greater id than /// lastMessageId /// /summary /// param nameclientPrivateToken/param /// param namelastMessageId/param /// returns/returns CometMessage[] GetMessages(string clientPrivateToken, long lastMessageId); /// summary /// Implementation of this method should queue a message for the specific client /// /summary /// param nameclientPublicToken/param /// param namename/param /// param namecontents/param void SendMessage(string clientPublicToken, string name, object contents); /// summary /// Implementation of this method should queue a message for all the clients /// /summary /// param namename/param /// param namecontents/param void SendMessage(string name, object contents); /// summary /// Implementation of this method should return a specific comet client /// /summary /// param nameclientPrivateToken/param /// returns/returns CometClient GetCometClient(string clientPrivateToken); /// summary /// Implementation of this method should remove a client from the cache /// /summary /// param nameclientPrivateToken/param void KillIdleCometClient(string clientPrivateToken); } } InProcCometStateProvider类 InProcCometStateProvider类实现了ICometStateProvider接口并且提供了一个很好的范例针对这个类我们可以想象很多很好的拓展诸如调用AO组件封装报警信息等等。 InProcCometStateProvider类包含类一个私有的内部类InProcCometStateProvider实际上可以理解为一种对消息的简单封装设计的时候考虑到需要关联CometClient和Message其实也可以单独作为一个外部类来设计。不过Adapter本身不应该太多关联类这样做也是权衡了一些拓展上的需求。 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MethodWorx.AspNetComet.Core { /// summary /// Class InProcCometStateProvider /// /// This class provides an implementation of ICometStateProvider that keeps the /// information in memory. This provider is not scalable as it will not run on a server /// farm but demonstrates how you should implemement the provider. /// /summary public class InProcCometStateProvider : ICometStateProvider { /// summary /// Private class which holds the state of each connected client /// /summary private class InProcCometClient { public CometClient CometClient; public Dictionarylong, CometMessage Messages new Dictionarylong, CometMessage(); public long NextMessageId 1; } /// summary /// Cache of clients /// /summary private Dictionarystring, InProcCometClient publicClients new Dictionarystring, InProcCometClient(); private Dictionarystring, InProcCometClient privateClients new Dictionarystring, InProcCometClient(); private static object state new object(); #region ICometStateProvider Members /// summary /// Store the new client in memory /// /summary /// param namecometClient/param public void InitializeClient(CometClient cometClient) { if (cometClient null) throw new ArgumentNullException(cometClient); lock (state) { // ok, ensure we dont already exist if (publicClients.ContainsKey(cometClient.PublicToken) || privateClients.ContainsKey(cometClient.PrivateToken)) throw CometException.CometClientAlreadyExistsException(); InProcCometClient inProcCometClient new InProcCometClient() { CometClient cometClient }; // stick the client int he arrays // ready to be used publicClients.Add(cometClient.PublicToken, inProcCometClient); privateClients.Add(cometClient.PrivateToken, inProcCometClient); } // ok, they are in there ready to be used } /// summary /// Get the messages for a specific client /// /summary /// param nameclientPrivateToken/param /// param namelastMessageId/param /// returns/returns public CometMessage[] GetMessages(string clientPrivateToken, long lastMessageId) { if(string.IsNullOrEmpty(clientPrivateToken)) throw new ArgumentNullException(clientPrivateToken); lock (state) { if (!privateClients.ContainsKey(clientPrivateToken)) throw CometException.CometClientDoesNotExistException(); // // ok, get the client InProcCometClient cometClient privateClients[clientPrivateToken]; Listlong toDelete new Listlong(); Listlong toReturn new Listlong(); // wicked, we have the client, so we can get its messages from our list // we delete any before the last messageId becuase we dont want them foreach(long key in cometClient.Messages.Keys) { if(key lastMessageId) toDelete.Add(key); else toReturn.Add(key); } // delete the ones from the messages foreach (long key in toDelete) { cometClient.Messages.Remove(key); } // and return the ones in the toReturn array ListCometMessage cometMessages new ListCometMessage(); foreach (long key in toReturn) { cometMessages.Add(cometClient.Messages[key]); } return cometMessages.ToArray(); } } /// summary /// Send a message to a specific client /// /summary /// param nameclientPublicToken/param /// param namename/param /// param namecontents/param public void SendMessage(string clientPublicToken, string name, object contents) { if (string.IsNullOrEmpty(clientPublicToken)) throw new ArgumentNullException(clientPublicToken); if (contents null) throw new ArgumentNullException(contents); lock (state) { if (!publicClients.ContainsKey(clientPublicToken)) throw CometException.CometClientDoesNotExistException(); // // ok, get the client InProcCometClient cometClient publicClients[clientPublicToken]; // ok, stick the message in the array CometMessage message new CometMessage(); message.Contents contents; message.Name name; message.MessageId cometClient.NextMessageId; // increment cometClient.NextMessageId; cometClient.Messages.Add(message.MessageId, message); } } /// summary /// Send a message to all the clients /// /summary /// param namename/param /// param namecontents/param public void SendMessage(string name, object contents) { if (contents null) throw new ArgumentNullException(contents); lock (state) { foreach (InProcCometClient cometClient in publicClients.Values) { // ok, stick the message in the array CometMessage message new CometMessage(); message.Contents contents; message.Name name; message.MessageId cometClient.NextMessageId; // increment cometClient.NextMessageId; cometClient.Messages.Add(message.MessageId, message); } } } /// summary /// Get the client from the state provider /// /summary /// param nameclientPrivateToken/param /// returns/returns public CometClient GetCometClient(string clientPrivateToken) { if (!this.privateClients.ContainsKey(clientPrivateToken)) throw CometException.CometClientDoesNotExistException(); // return the client private token return this.privateClients[clientPrivateToken].CometClient; } /// summary /// Remove an idle client from the memory /// /summary /// param nameclientPrivateToken/param public void KillIdleCometClient(string clientPrivateToken) { if (!this.privateClients.ContainsKey(clientPrivateToken)) throw CometException.CometClientDoesNotExistException(); // get the client InProcCometClient ipCometClient this.privateClients[clientPrivateToken]; // and remove the dictionarys this.privateClients.Remove(ipCometClient.CometClient.PrivateToken); this.publicClients.Remove(ipCometClient.CometClient.PublicToken); } #endregion } } PS:可以说这篇随笔中将COMET IM的几个最容易拓展的类进行了介绍核心部分将在下一篇随笔中进行讲解欢迎大家讨论并拍砖。同时预祝大家春节愉快 转载于:https://www.cnblogs.com/lzlynn/archive/2009/01/21/1379575.html