Connection类之ConnectionDelegatesHandlers.cs(NetworkComms 2.3.1源码了解和学习)

networkComms.net2.3.1开源版本,基于gpl V3协议。因为不能公开3.x版本的源码,所以基于此版本进行学习。3.X版本进行了诸多改进和Bug修复,使用方法上两者相差不大。
namespace NetworkCommsDotNet
{
    /// <summary>
    /// Connection对象  这个类是TcpConnection和 UDPConnnection连接类的父类
    /// Connection由以下五个文件组成 大家注意到每个类前面都有个 partial关键字
    /// ConnectionCreate.cs <1>
    /// ConnectionDelegatesHandlers.cs <2>
    /// ConnectionIncomingData.cs <3>
    /// ConnectionSendClose.cs <4>
    /// ConnectionStatic.cs  <5>
    /// </summary>
    public abstract partial class Connection
    {
        /// <summary>
        ///线程安全锁
        /// </summary>
        protected object delegateLocker = new object();

        /// <summary>
        /// 默认的收发参数
        /// </summary>
        public SendReceiveOptions ConnectionDefaultSendReceiveOptions { get; protected set; }

        /// <summary>
        /// 一个与连接关闭相关的委托
        /// </summary>
        private NetworkComms.ConnectionEstablishShutdownDelegate ConnectionSpecificShutdownDelegate { get; set; }

        /// <summary>
        /// By default all incoming objects are handled using ConnectionDefaultSendReceiveOptions. Should the user want something else
        /// those settings are stored here
        /// </summary>
        private Dictionary<string, PacketTypeUnwrapper> incomingPacketUnwrappers = new Dictionary<string, PacketTypeUnwrapper>();

        /// <summary>
        /// A connection specific incoming packet handler dictionary. These are called before any global handlers
        /// </summary>
        private Dictionary<string, List<IPacketTypeHandlerDelegateWrapper>> incomingPacketHandlers = new Dictionary<string, List<IPacketTypeHandlerDelegateWrapper>>();

        /// <summary>
        /// Returns the <see cref="SendReceiveOptions"/> to be used for the provided <see cref="PacketHeader"/>. Ensures there will not be a serializer / data processor clash for different delegate levels.
        /// </summary>
        /// <param name="header">The <see cref="PacketHeader"/> options are desired.</param>
        /// <returns>The requested <see cref="SendReceiveOptions"/></returns>
        private SendReceiveOptions IncomingPacketSendReceiveOptions(PacketHeader header)
        {
            //Are there connection specific or global packet handlers?
            bool connectionSpecificHandlers = false;
            lock (delegateLocker) connectionSpecificHandlers = incomingPacketHandlers.ContainsKey(header.PacketType);

            bool globalHandlers = NetworkComms.GlobalIncomingPacketHandlerExists(header.PacketType);

            //Get connection specific options for this packet type, if there arn't any use the connection default options
            SendReceiveOptions connectionSpecificOptions = PacketTypeUnwrapperOptions(header.PacketType);
            if (connectionSpecificOptions == null) connectionSpecificOptions = ConnectionDefaultSendReceiveOptions;

            //Get global options for this packet type, if there arn't any use the global default options
            SendReceiveOptions globalOptions = NetworkComms.GlobalPacketTypeUnwrapperOptions(header.PacketType);
            if (globalOptions == null) globalOptions = NetworkComms.DefaultSendReceiveOptions;

            if (connectionSpecificHandlers && globalHandlers)
            {
                if (!connectionSpecificOptions.OptionsCompatible(globalOptions))
                    throw new PacketHandlerException("Attempted to determine correct sendReceiveOptions for packet of type '" + header.PacketType + "'. Unable to continue as connection specific and global sendReceiveOptions are not equal.");

                //We need to combine options in this case using the connection specific option in preference if both are present
                var combinedOptions = new Dictionary<string, string>(globalOptions.Options);
                
                foreach (var pair in connectionSpecificOptions.Options)
                    combinedOptions[pair.Key] = pair.Value;

                //If the header specifies a serializer and data processors we will autodetect those
                if (header.ContainsOption(PacketHeaderLongItems.SerializerProcessors))
                {
                    DataSerializer serializer;
                    List<DataProcessor> dataProcessors;

                    DPSManager.GetSerializerDataProcessorsFromIdentifier(header.GetOption(PacketHeaderLongItems.SerializerProcessors), out serializer, out dataProcessors);
                    return new SendReceiveOptions(serializer, dataProcessors, combinedOptions);
                }

                //Otherwise we will use options that were specified
                return new SendReceiveOptions(connectionSpecificOptions.DataSerializer, connectionSpecificOptions.DataProcessors, combinedOptions);
            }
            else if (connectionSpecificHandlers)
            {
                //If the header specifies a serializer and data processors we will autodetect those
                if (header.ContainsOption(PacketHeaderLongItems.SerializerProcessors))
                {
                    DataSerializer serializer;
                    List<DataProcessor> dataProcessors;

                    DPSManager.GetSerializerDataProcessorsFromIdentifier(header.GetOption(PacketHeaderLongItems.SerializerProcessors), out serializer, out dataProcessors);
                    return new SendReceiveOptions(serializer, dataProcessors, connectionSpecificOptions.Options);
                }

                return connectionSpecificOptions;
            }
            else
            {
                //If the header specifies a serializer and data processors we will autodetect those
                if (header.ContainsOption(PacketHeaderLongItems.SerializerProcessors))
                {
                    DataSerializer serializer;
                    List<DataProcessor> dataProcessors;

                    DPSManager.GetSerializerDataProcessorsFromIdentifier(header.GetOption(PacketHeaderLongItems.SerializerProcessors), out serializer, out dataProcessors);
                    return new SendReceiveOptions(serializer, dataProcessors, globalOptions.Options);
                }

                //If just globalHandlers is set (or indeed no handlers atall we just return the global options
                return globalOptions;
            }
        }

        /// <summary>
        /// Trigger connection specific packet delegates with the provided parameters. Returns true if connection specific handlers were executed.
        /// </summary>
        /// <param name="packetHeader">The packetHeader for which all delegates should be triggered with</param>
        /// <param name="incomingObjectBytes">The serialised and or compressed bytes to be used</param>
        /// <param name="options">The incoming sendReceiveOptions to use overriding defaults</param>
        /// <returns>Returns true if connection specific handlers were executed.</returns>
        public bool TriggerSpecificPacketHandlers(PacketHeader packetHeader, MemoryStream incomingObjectBytes, SendReceiveOptions options)
        {
            try
            {
                if (packetHeader == null) throw new ArgumentNullException("packetHeader", "Provided PacketHeader cannot not be null.");
                if (incomingObjectBytes == null) throw new ArgumentNullException("incomingObjectBytes", "Provided MemoryStream cannot not be null for packetType " + packetHeader.PacketType);
                if (options == null) throw new ArgumentNullException("options", "Provided SendReceiveOptions cannot not be null for packetType " + packetHeader.PacketType);

                //We take a copy of the handlers list incase it is modified outside of the lock
                List<IPacketTypeHandlerDelegateWrapper> handlersCopy = null;
                lock (delegateLocker)
                    if (incomingPacketHandlers.ContainsKey(packetHeader.PacketType))
                        handlersCopy = new List<IPacketTypeHandlerDelegateWrapper>(incomingPacketHandlers[packetHeader.PacketType]);

                if (handlersCopy == null)
                    //If we have received an unknown packet type we ignore them on this connection specific level and just finish here
                    return false;
                else
                {
                    //Idiot check
                    if (handlersCopy.Count == 0) throw new PacketHandlerException("An entry exists in the packetHandlers list but it contains no elements. This should not be possible.");

                    //Deserialise the object only once
                    object returnObject = handlersCopy[0].DeSerialize(incomingObjectBytes, options);

                    //Pass the data onto the handler and move on.
                    if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... passing completed data packet to selected connection specific handlers.");

                    //Pass the object to all necessary delgates
                    //We need to use a copy because we may modify the original delegate list during processing
                    foreach (IPacketTypeHandlerDelegateWrapper wrapper in handlersCopy)
                    {
                        try
                        {
                            wrapper.Process(packetHeader, this, returnObject);
                        }
                        catch (Exception ex)
                        {
                            if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Fatal("An unhandled exception was caught while processing a packet handler for a packet type '" + packetHeader.PacketType + "'. Make sure to catch errors in packet handlers. See error log file for more information.");
                            NetworkComms.LogError(ex, "PacketHandlerErrorSpecific_" + packetHeader.PacketType);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                //If anything goes wrong here all we can really do is log the exception
                if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Fatal("An exception occured in TriggerPacketHandler() for a packet type '" + packetHeader.PacketType + "'. See error log file for more information.");
                NetworkComms.LogError(ex, "PacketHandlerErrorSpecific_" + packetHeader.PacketType);
            }

            return true;
        }

        /// <summary>
        /// Returns the packet type sendReceiveOptions possibly used to unwrap incoming data. If no specific options are registered returns null
        /// </summary>
        /// <param name="packetTypeStr">The packet type for which the <see cref="SendReceiveOptions"/> are required.</param>
        /// <returns>The requested <see cref="SendReceiveOptions"/> otherwise null</returns>
        public SendReceiveOptions PacketTypeUnwrapperOptions(string packetTypeStr)
        {
            SendReceiveOptions options = null;

            //If we find a global packet unwrapper for this packetType we used those options
            lock (delegateLocker)
            {
                if (incomingPacketUnwrappers.ContainsKey(packetTypeStr))
                    options = incomingPacketUnwrappers[packetTypeStr].Options;
            }

            return options;
        }

        /// <summary>
        /// Append a connection specific packet handler
        /// </summary>
        /// <typeparam name="T">The type of incoming object</typeparam>
        /// <param name="packetTypeStr">The packet type for which this handler will be executed</param>
        /// <param name="packetHandlerDelgatePointer">The delegate to be executed when a packet of packetTypeStr is received</param>
        /// <param name="options">The <see cref="SendReceiveOptions"/> to be used for the provided packet type</param>
        public void AppendIncomingPacketHandler<T>(string packetTypeStr, NetworkComms.PacketHandlerCallBackDelegate<T> packetHandlerDelgatePointer, SendReceiveOptions options)
        {
            if (packetTypeStr == null) throw new ArgumentNullException("packetTypeStr", "Provided packetType string cannot be null.");
            if (packetHandlerDelgatePointer == null) throw new ArgumentNullException("packetHandlerDelgatePointer", "Provided NetworkComms.PacketHandlerCallBackDelegate<T> cannot be null.");
            if (options == null) throw new ArgumentNullException("options", "Provided SendReceiveOptions cannot be null.");

            lock (delegateLocker)
            {
                if (incomingPacketUnwrappers.ContainsKey(packetTypeStr))
                {
                    //Make sure if we already have an existing entry that it matches with the provided
                    if (!incomingPacketUnwrappers[packetTypeStr].Options.OptionsCompatible(options))
                        throw new PacketHandlerException("The proivded SendReceiveOptions are not compatible with existing SendReceiveOptions already specified for this packetTypeStr.");
                }
                else
                    incomingPacketUnwrappers.Add(packetTypeStr, new PacketTypeUnwrapper(packetTypeStr, options));             

                //Ad the handler to the list
                if (incomingPacketHandlers.ContainsKey(packetTypeStr))
                {
                    //Make sure we avoid duplicates
                    PacketTypeHandlerDelegateWrapper<T> toCompareDelegate = new PacketTypeHandlerDelegateWrapper<T>(packetHandlerDelgatePointer);
                    bool delegateAlreadyExists = false;
                    foreach (var handler in incomingPacketHandlers[packetTypeStr])
                    {
                        if (handler == toCompareDelegate)
                        {
                            delegateAlreadyExists = true;
                            break;
                        }
                    }
                        
                    if (delegateAlreadyExists)
                        throw new PacketHandlerException("This specific packet handler delegate already exists for the provided packetTypeStr.");

                    incomingPacketHandlers[packetTypeStr].Add(new PacketTypeHandlerDelegateWrapper<T>(packetHandlerDelgatePointer));
                }
                else
                    incomingPacketHandlers.Add(packetTypeStr, new List<IPacketTypeHandlerDelegateWrapper>() { new PacketTypeHandlerDelegateWrapper<T>(packetHandlerDelgatePointer) });

                if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Info("Added connection specific incoming packetHandler for '" + packetTypeStr + "' packetType with " + ConnectionInfo);
            }
        }

        /// <summary>
        /// Returns true if a packet handler exists for the provided packet type, on this connection
        /// </summary>
        /// <param name="packetTypeStr">The packet type for which to check incoming packet handlers</param>
        /// <returns>True if a packet handler exists</returns>
        public bool IncomingPacketHandlerExists(string packetTypeStr)
        {
            lock (delegateLocker)
                return incomingPacketHandlers.ContainsKey(packetTypeStr);
        }

        /// <summary>
        /// Returns true if the provided packet handler has been added for the provided packet type, on this connection.
        /// </summary>
        /// <param name="packetTypeStr">The packet type within which to check packet handlers</param>
        /// <param name="packetHandlerDelgatePointer">The packet handler to look for</param>
        /// <returns>True if a global packet handler exists for the provided packetType</returns>
        public bool IncomingPacketHandlerExists(string packetTypeStr, Delegate packetHandlerDelgatePointer)
        {
            lock (delegateLocker)
            {
                if (incomingPacketHandlers.ContainsKey(packetTypeStr))
                {
                    foreach (var handler in incomingPacketHandlers[packetTypeStr])
                        if (handler.EqualsDelegate(packetHandlerDelgatePointer))
                            return true;
                }
            }

            return false;
        }

        /// <summary>
        /// Remove the provided delegate for the specified packet type
        /// </summary>
        /// <param name="packetTypeStr">Packet type for which this delegate should be removed</param>
        /// <param name="packetHandlerDelgatePointer">The delegate to remove</param>
        public void RemoveIncomingPacketHandler(string packetTypeStr, Delegate packetHandlerDelgatePointer)
        {
            lock (delegateLocker)
            {
                if (incomingPacketHandlers.ContainsKey(packetTypeStr))
                {
                    //Remove any instances of this handler from the delegates
                    //The bonus here is if the delegate has not been added we continue quite happily
                    IPacketTypeHandlerDelegateWrapper toRemove = null;

                    foreach (var handler in incomingPacketHandlers[packetTypeStr])
                    {
                        if (handler.EqualsDelegate(packetHandlerDelgatePointer))
                        {
                            toRemove = handler;
                            break;
                        }
                    }

                    if (toRemove != null)
                        incomingPacketHandlers[packetTypeStr].Remove(toRemove);

                    if (incomingPacketHandlers[packetTypeStr] == null || incomingPacketHandlers[packetTypeStr].Count == 0)
                    {
                        incomingPacketHandlers.Remove(packetTypeStr);

                        //Remove any entries in the unwrappers dict as well as we are done with this packetTypeStr
                        if (incomingPacketHandlers.ContainsKey(packetTypeStr))
                            incomingPacketHandlers.Remove(packetTypeStr);

                        if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Info("Removed a connection specific packetHandler for '" + packetTypeStr + "' packetType. No handlers remain with " + ConnectionInfo);
                    }
                    else
                        if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Info("Removed a connection specific packetHandler for '" + packetTypeStr + "' packetType. Handlers remain with " + ConnectionInfo);
                }
            }
        }

        /// <summary>
        /// Removes all delegates for the provided packet type
        /// </summary>
        /// <param name="packetTypeStr">Packet type for which all delegates should be removed</param>
        public void RemoveIncomingPacketHandler(string packetTypeStr)
        {
            lock (delegateLocker)
            {
                //We don't need to check for potentially removing a critical reserved packet handler here because those cannot be removed.
                if (incomingPacketHandlers.ContainsKey(packetTypeStr))
                {
                    incomingPacketHandlers.Remove(packetTypeStr);

                    if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Info("Removed all connection specific incoming packetHandlers for '" + packetTypeStr + "' packetType with " + ConnectionInfo);
                }
            }
        }

        /// <summary>
        /// Removes all delegates for all packet types
        /// </summary>
        public void RemoveIncomingPacketHandler()
        {
            lock (delegateLocker)
            {
                incomingPacketHandlers = new Dictionary<string, List<IPacketTypeHandlerDelegateWrapper>>();

                if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Info("Removed all connection specific incoming packetHandlers for all packetTypes with " + ConnectionInfo);
            }
        }

        /// <summary>
        /// Add a connection specific shutdown delegate
        /// </summary>
        /// <param name="handlerToAppend">The delegate to call when a connection is shutdown</param>
        public void AppendShutdownHandler(NetworkComms.ConnectionEstablishShutdownDelegate handlerToAppend)
        {
            lock (delegateLocker)
            {
                if (ConnectionSpecificShutdownDelegate == null)
                    ConnectionSpecificShutdownDelegate = handlerToAppend;
                else
                    ConnectionSpecificShutdownDelegate += handlerToAppend;

                if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Debug("Added a connection specific shutdown delegate to connection with " + ConnectionInfo);
            }
        }

        /// <summary>
        /// Remove a connection specific shutdown delegate.
        /// </summary>
        /// <param name="handlerToRemove">The delegate to remove for shutdown events</param>
        public void RemoveShutdownHandler(NetworkComms.ConnectionEstablishShutdownDelegate handlerToRemove)
        {
            lock (delegateLocker)
            {
                ConnectionSpecificShutdownDelegate -= handlerToRemove;
                if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Debug("Removed ConnectionSpecificShutdownDelegate to connection with " + ConnectionInfo);

                if (ConnectionSpecificShutdownDelegate == null)
                {
                    if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Info("No handlers remain for ConnectionSpecificShutdownDelegate with " + ConnectionInfo);
                }
                else
                {
                    if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Info("Handlers remain for ConnectionSpecificShutdownDelegate with " + ConnectionInfo);
                }
            }
        }
    }
}

 

来自英国剑桥的c#网络通讯框架  开源版本: networkcomms2.3.1  可以进入此页面下载 networkcomms网络通讯框架学习 

【开源下载】基于TCP网络通信的即时聊天系统(IM系统)(c#源码)

[源码下载]Demo2.模拟简单登陆-效果图 基于networkcomms2.3.1

[源码下载]Demo1 客户端从服务器获取信息(基于networkcomms2.3.1)

【开源下载】基于TCP网络通信的自动升级程序c#源码

【模板下载】分享我所使用的数据库框架

【模板下载】innosetup 制作.net安装包的模板

 

【模板下载】分享我所使用的数据库框架

你可能感兴趣的:(Connection类之ConnectionDelegatesHandlers.cs(NetworkComms 2.3.1源码了解和学习))