您的位置:首页 > 其它

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

2015-03-03 00:00 447 查看
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安装包的模板

【模板下载】分享我所使用的数据库框架
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: