介绍开源的.net通信框架NetworkComms框架 源码分析ConnectionInfo
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了介绍开源的.net通信框架NetworkComms框架 源码分析ConnectionInfo相关的知识,希望对你有一定的参考价值。
原文网址: http://www.cnblogs.com/csdev
Networkcomms 是一款C# 语言编写的TCP/UDP通信框架 作者是英国人 以前是收费的 目前作者已经开源 许可是:Apache License v2
开源地址是:https://github.com/MarcFletcher/NetworkComms.Net
ConnectionInfo 是连接的信息类 用来存放连接类型(TCP,UDP),连接ID,创建连接时间,是否服务器端,本地地址,远端地址,最近通信时间,等信息的类
/// <summary> /// Contains any information related to the configuration of a <see cref="Connection"/> object. /// 连接信息类 包含一个连接的相关配置信息 /// </summary> public class ConnectionInfo : IEquatable<ConnectionInfo>, IExplicitlySerialize { /// <summary> /// The type of this connection /// 连接类型 比如TCP或者UDP /// </summary> public ConnectionType ConnectionType { get; internal set; } /// <summary> /// We store our unique peer identifier as a string so that it can be easily serialised. /// 网络ID /// 每一个连接都有一个 ShortGuid类型的网络ID 此处把网络ID转化为字符类型了 /// </summary> string NetworkIdentifierStr; //有一些类不支持直接序列化 比如 Image,IPEndPoint 我们又希望传递其信息 要做一些变通 //image类一般我们把他转成字节数据再序列化 string localEndPointAddressStr; //Only set on serialise 序列化时设置 int localEndPointPort; //Only set on serialise 序列化时设置 bool hashCodeCacheSet = false; int hashCodeCache; /// <summary> /// True if the <see cref="RemoteEndPoint"/> is connectable. /// 是否可连接 True 代表可连接 /// </summary> public bool IsConnectable { get; private set; } /// <summary> /// The DateTime corresponding to the creation time of this connection object /// 连接创建时间 /// </summary> public DateTime ConnectionCreationTime { get; protected set; } /// <summary> /// True if connection was originally established by remote /// 是否为服务器端 /// </summary> public bool ServerSide { get; internal set; } /// <summary> /// If this connection is <see cref="ServerSide"/> references the listener that was used. /// 如果为服务器端 相关联的连接监听基类 /// </summary> public ConnectionListenerBase ConnectionListener { get; internal set; } /// <summary> /// The DateTime corresponding to the creation time of this connection object /// 连接创建完成时间 /// </summary> public DateTime ConnectionEstablishedTime { get; private set; } /// <summary> /// The <see cref="EndPoint"/> corresponding to the local end of this connection. /// 连接对应的本地端点 /// </summary> public EndPoint LocalEndPoint { get; private set; } /// <summary> /// The <see cref="EndPoint"/> corresponding to the local end of this connection. /// 连接对应的远程端点 /// </summary> public EndPoint RemoteEndPoint { get; private set; } /// <summary> /// Describes the current state of the connection /// 连接状态 /// </summary> public ConnectionState ConnectionState { get; private set; } /// <summary> /// Returns the networkIdentifier of this peer as a ShortGuid. If the NetworkIdentifier has not yet been set returns ShortGuid.Empty. /// 返回 ShortGuid类型的网络ID /// </summary> public ShortGuid NetworkIdentifier { get { if (NetworkIdentifierStr == null || NetworkIdentifierStr == "") return ShortGuid.Empty; else return new ShortGuid(NetworkIdentifierStr); } } DateTime lastTrafficTime; object internalLocker = new object(); /// <summary> /// The DateTime corresponding to the time data was sent or received /// 连接上的数据最近的更新时间 /// </summary> public DateTime LastTrafficTime { get { lock (internalLocker) return lastTrafficTime; } protected set { lock (internalLocker) lastTrafficTime = value; } } /// <summary> /// If enabled NetworkComms.Net uses a custom application layer protocol to provide /// useful features such as inline serialisation, transparent packet transmission, /// remote peer information etc. Default: ApplicationLayerProtocolStatus.Enabled /// 应用层协议状态 默认启用 启用后可以使用networkcomms提供的内部序列化,透明数据包传送等功能 /// </summary> public ApplicationLayerProtocolStatus ApplicationLayerProtocol { get; private set; } #region Internal Usages /// <summary> /// The localEndPoint cast as <see cref="IPEndPoint"/>. /// 本地端点 /// </summary> internal IPEndPoint LocalIPEndPoint { get { try { return (IPEndPoint)LocalEndPoint; } catch (InvalidCastException ex) { throw new InvalidCastException("Unable to cast LocalEndPoint to IPEndPoint.", ex); } } } /// <summary> /// The remoteEndPoint cast as <see cref="IPEndPoint"/>. /// 远程端点 /// </summary> internal IPEndPoint RemoteIPEndPoint { get { try { return (IPEndPoint)RemoteEndPoint; } catch (InvalidCastException ex) { throw new InvalidCastException("Unable to cast LocalEndPoint to IPEndPoint.", ex); } } } #if NET4 || NET35 /// <summary> /// The localEndPoint cast as <see cref="IPEndPoint"/>. /// </summary> internal BluetoothEndPoint LocalBTEndPoint { get { try { return (BluetoothEndPoint)LocalEndPoint; } catch (InvalidCastException ex) { throw new InvalidCastException("Unable to cast LocalEndPoint to IPEndPoint.", ex); } } } /// <summary> /// The remoteEndPoint cast as <see cref="IPEndPoint"/>. /// </summary> internal BluetoothEndPoint RemoteBTEndPoint { get { try { return (BluetoothEndPoint)RemoteEndPoint; } catch (InvalidCastException ex) { throw new InvalidCastException("Unable to cast LocalEndPoint to IPEndPoint.", ex); } } } #endif #endregion /// <summary> /// Private constructor required for deserialisation. /// 私有构造器 反序列化时需使用 /// </summary> #if android || ios [Preserve] #endif private ConnectionInfo() { } /// <summary> /// Create a new ConnectionInfo object pointing at the provided remote <see cref="IPEndPoint"/>. /// Uses the custom NetworkComms.Net application layer protocol. /// 根据目标端点,创建一个连接对象 启用networkcomms.net应用层协议 /// </summary> /// <param name="remoteEndPoint">The end point corresponding with the remote target</param> public ConnectionInfo(EndPoint remoteEndPoint) { this.RemoteEndPoint = remoteEndPoint; switch (remoteEndPoint.AddressFamily) { case AddressFamily.InterNetwork: this.LocalEndPoint = new IPEndPoint(IPAddress.Any, 0); break; case AddressFamily.InterNetworkV6: this.LocalEndPoint = new IPEndPoint(IPAddress.IPv6Any, 0); break; #if NET4 || NET35 case (AddressFamily)32: this.LocalEndPoint = new BluetoothEndPoint(BluetoothAddress.None, BluetoothService.SerialPort); break; #endif } this.ConnectionCreationTime = DateTime.Now; this.ApplicationLayerProtocol = ApplicationLayerProtocolStatus.Enabled; } /// <summary> /// Create a new ConnectionInfo object pointing at the provided remote <see cref="IPEndPoint"/> 根据远程端点创建一个连接信息对象 /// </summary> /// <param name="remoteEndPoint">The end point corresponding with the remote target 远程端点</param> /// <param name="applicationLayerProtocol">If enabled NetworkComms.Net uses a custom /// application layer protocol to provide useful features such as inline serialisation, /// transparent packet transmission, remote peer handshake and information etc. We strongly /// recommend you enable the NetworkComms.Net application layer protocol. 应用层协议(前面已介绍)</param> public ConnectionInfo(EndPoint remoteEndPoint, ApplicationLayerProtocolStatus applicationLayerProtocol) { if (applicationLayerProtocol == ApplicationLayerProtocolStatus.Undefined) throw new ArgumentException("A value of ApplicationLayerProtocolStatus.Undefined is invalid when creating instance of ConnectionInfo.", "applicationLayerProtocol"); this.RemoteEndPoint = remoteEndPoint; switch (remoteEndPoint.AddressFamily) { case AddressFamily.InterNetwork: this.LocalEndPoint = new IPEndPoint(IPAddress.Any, 0); break; case AddressFamily.InterNetworkV6: this.LocalEndPoint = new IPEndPoint(IPAddress.IPv6Any, 0); break; #if NET4 || NET35 case (AddressFamily)32: this.LocalEndPoint = new BluetoothEndPoint(BluetoothAddress.None, BluetoothService.SerialPort); break; #endif } this.ConnectionCreationTime = DateTime.Now; this.ApplicationLayerProtocol = applicationLayerProtocol; } /// <summary> /// Create a new ConnectionInfo object pointing at the provided remote ipAddress and port. /// Provided ipAddress and port are parsed in to <see cref="RemoteEndPoint"/>. Uses the /// custom NetworkComms.Net application layer protocol. /// 根据远程IP地址和端口号创建连接对象 /// </summary> /// <param name="remoteIPAddress">IP地址 IP address of the remote target in string format, e.g. "192.168.0.1" </param> /// <param name="remotePort">端口号 The available port of the remote target. /// Valid ports are 1 through 65535. Port numbers less than 256 are reserved for well-known services (like HTTP on port 80) and port numbers less than 1024 generally require admin access</param> public ConnectionInfo(string remoteIPAddress, int remotePort) { IPAddress ipAddress; if (!IPAddress.TryParse(remoteIPAddress, out ipAddress)) throw new ArgumentException("Provided remoteIPAddress string was not successfully parsed.", "remoteIPAddress"); this.RemoteEndPoint = new IPEndPoint(ipAddress, remotePort); switch (this.RemoteEndPoint.AddressFamily) { case AddressFamily.InterNetwork: this.LocalEndPoint = new IPEndPoint(IPAddress.Any, 0); break; case AddressFamily.InterNetworkV6: this.LocalEndPoint = new IPEndPoint(IPAddress.IPv6Any, 0); break; #if NET4 || NET35 case (AddressFamily)32: this.LocalEndPoint = new BluetoothEndPoint(BluetoothAddress.None, BluetoothService.SerialPort); break; #endif } this.ConnectionCreationTime = DateTime.Now; this.ApplicationLayerProtocol = ApplicationLayerProtocolStatus.Enabled; } /// <summary> /// Create a new ConnectionInfo object pointing at the provided remote ipAddress and port. /// Provided ipAddress and port are parsed in to <see cref="RemoteEndPoint"/>. /// 根据远程IP地址和端口号创建连接对象 /// </summary> /// <param name="remoteIPAddress">IP地址 IP address of the remote target in string format, e.g. "192.168.0.1"</param> /// <param name="remotePort">端口号 The available port of the remote target. /// Valid ports are 1 through 65535. Port numbers less than 256 are reserved for well-known services (like HTTP on port 80) and port numbers less than 1024 generally require admin access</param> /// <param name="applicationLayerProtocol">If enabled NetworkComms.Net uses a custom /// application layer protocol to provide useful features such as inline serialisation, /// transparent packet transmission, remote peer handshake and information etc. We strongly /// recommend you enable the NetworkComms.Net application layer protocol.</param> public ConnectionInfo(string remoteIPAddress, int remotePort, ApplicationLayerProtocolStatus applicationLayerProtocol) { if (applicationLayerProtocol == ApplicationLayerProtocolStatus.Undefined) throw new ArgumentException("A value of ApplicationLayerProtocolStatus.Undefined is invalid when creating instance of ConnectionInfo.", "applicationLayerProtocol"); IPAddress ipAddress; if (!IPAddress.TryParse(remoteIPAddress, out ipAddress)) throw new ArgumentException("Provided remoteIPAddress string was not successfully parsed.", "remoteIPAddress"); this.RemoteEndPoint = new IPEndPoint(ipAddress, remotePort); switch (this.RemoteEndPoint.AddressFamily) { case AddressFamily.InterNetwork: this.LocalEndPoint = new IPEndPoint(IPAddress.Any, 0); break; case AddressFamily.InterNetworkV6: this.LocalEndPoint = new IPEndPoint(IPAddress.IPv6Any, 0); break; #if NET4 || NET35 case (AddressFamily)32: this.LocalEndPoint = new BluetoothEndPoint(BluetoothAddress.None, BluetoothService.SerialPort); break; #endif } this.ConnectionCreationTime = DateTime.Now; this.ApplicationLayerProtocol = applicationLayerProtocol; } /// <summary> /// Create a connectionInfo object which can be used to inform a remote peer of local connectivity. /// Uses the custom NetworkComms.Net application layer protocol. /// 创建一个连接对象 设定了本地端点 可用于与远程端点进行连接 /// 启用了自定义应用层协议 /// </summary> /// <param name="connectionType">连接类型 The type of connection</param> /// <param name="localNetworkIdentifier">本地网络ID The local network identifier</param> /// <param name="localEndPoint">本地端点 The localEndPoint which should be referenced remotely</param> /// <param name="isConnectable">是否可连接 True if connectable on provided localEndPoint</param> public ConnectionInfo(ConnectionType connectionType, ShortGuid localNetworkIdentifier, EndPoint localEndPoint, bool isConnectable) { if (localEndPoint == null) throw new ArgumentNullException("localEndPoint", "localEndPoint may not be null"); this.ConnectionType = connectionType; this.NetworkIdentifierStr = localNetworkIdentifier.ToString(); switch (localEndPoint.AddressFamily) { case AddressFamily.InterNetwork: this.RemoteEndPoint = new IPEndPoint(IPAddress.Any, 0); break; case AddressFamily.InterNetworkV6: this.RemoteEndPoint = new IPEndPoint(IPAddress.IPv6Any, 0); break; #if NET4 || NET35 case (AddressFamily)32: this.RemoteEndPoint = new BluetoothEndPoint(BluetoothAddress.None, BluetoothService.SerialPort); break; #endif } this.LocalEndPoint = localEndPoint; this.IsConnectable = isConnectable; this.ApplicationLayerProtocol = ApplicationLayerProtocolStatus.Enabled; } /// <summary> /// Create a connectionInfo object which can be used to inform a remote peer of local connectivity /// 创建一个连接对象 设定了本地端点 可用于与远程端点进行连接 /// </summary> /// <param name="connectionType">连接类型 The type of connection</param> /// <param name="localNetworkIdentifier">本地网络ID The local network identifier</param> /// <param name="localEndPoint">本地端点 The localEndPoint which should be referenced remotely</param> /// <param name="isConnectable">是否可连接 True if connectable on provided localEndPoint</param> /// <param name="applicationLayerProtocol">应用层协议 If enabled NetworkComms.Net uses a custom /// application layer protocol to provide useful features such as inline serialisation, /// transparent packet transmission, remote peer handshake and information etc. We strongly /// recommend you enable the NetworkComms.Net application layer protocol.</param> public ConnectionInfo(ConnectionType connectionType, ShortGuid localNetworkIdentifier, EndPoint localEndPoint, bool isConnectable, ApplicationLayerProtocolStatus applicationLayerProtocol) { if (localEndPoint == null) throw new ArgumentNullException("localEndPoint", "localEndPoint may not be null"); if (applicationLayerProtocol == ApplicationLayerProtocolStatus.Undefined) throw new ArgumentException("A value of ApplicationLayerProtocolStatus.Undefined is invalid when creating instance of ConnectionInfo.", "applicationLayerProtocol"); this.ConnectionType = connectionType; this.NetworkIdentifierStr = localNetworkIdentifier.ToString(); this.LocalEndPoint = localEndPoint; switch (localEndPoint.AddressFamily) { case AddressFamily.InterNetwork: this.RemoteEndPoint = new IPEndPoint(IPAddress.Any, 0); break; case AddressFamily.InterNetworkV6: this.RemoteEndPoint = new IPEndPoint(IPAddress.IPv6Any, 0); break; #if NET4 || NET35 case (AddressFamily)32: this.RemoteEndPoint = new BluetoothEndPoint(BluetoothAddress.None, BluetoothService.SerialPort); break; #endif } this.IsConnectable = isConnectable; this.ApplicationLayerProtocol = applicationLayerProtocol; } /// <summary> /// Create a connectionInfo object for a new connection. /// 为新的连接创建一个连接对象 /// </summary> /// <param name="connectionType">连接类型 The type of connection</param> /// <param name="remoteEndPoint">远端点 The remoteEndPoint of this connection</param> /// <param name="localEndPoint">本地端点 The localEndpoint of this connection</param> /// <param name="applicationLayerProtocol">应用层协议 If enabled NetworkComms.Net uses a custom /// application layer protocol to provide useful features such as inline serialisation, /// transparent packet transmission, remote peer handshake and information etc. We strongly /// recommend you enable the NetworkComms.Net application layer protocol.</param> /// <param name="connectionListener">The listener associated with this connection if server side</param> internal ConnectionInfo(ConnectionType connectionType, EndPoint remoteEndPoint, EndPoint localEndPoint, ApplicationLayerProtocolStatus applicationLayerProtocol = ApplicationLayerProtocolStatus.Enabled, ConnectionListenerBase connectionListener = null) { if (localEndPoint == null) throw new ArgumentNullException("localEndPoint", "localEndPoint may not be null"); if (remoteEndPoint == null) throw new ArgumentNullException("remoteEndPoint", "remoteEndPoint may not be null"); if (applicationLayerProtocol == ApplicationLayerProtocolStatus.Undefined) throw new ArgumentException("A value of ApplicationLayerProtocolStatus.Undefined is invalid when creating instance of ConnectionInfo.", "applicationLayerProtocol"); this.ServerSide = (connectionListener!=null); this.ConnectionListener = connectionListener; this.ConnectionType = connectionType; this.RemoteEndPoint = remoteEndPoint; this.LocalEndPoint = localEndPoint; this.ConnectionCreationTime = DateTime.Now; this.ApplicationLayerProtocol = applicationLayerProtocol; } /// <summary> /// Marks the connection as establishing /// 标记连接在创建中 /// </summary> internal void NoteStartConnectionEstablish() { lock(internalLocker) { if (ConnectionState == ConnectionState.Shutdown) throw new ConnectionSetupException("Unable to mark as establishing as connection has already shutdown."); if (ConnectionState == ConnectionState.Establishing) throw new ConnectionSetupException("Connection already marked as establishing"); else ConnectionState = ConnectionState.Establishing; } } /// <summary> /// Set this connectionInfo as established. /// 设置连接信息类中连接状态为已经创建 /// </summary> internal void NoteCompleteConnectionEstablish() { lock (internalLocker) { if (ConnectionState == ConnectionState.Shutdown) throw new ConnectionSetupException("Unable to mark as established as connection has already shutdown."); if (!(ConnectionState == ConnectionState.Establishing)) throw new ConnectionSetupException("Connection should be marked as establishing before calling CompleteConnectionEstablish"); if (ConnectionState == ConnectionState.Established) throw new ConnectionSetupException("Connection already marked as established."); ConnectionState = ConnectionState.Established; ConnectionEstablishedTime = DateTime.Now; //The below only really applied to TCP connections 以下只适用于TCP连接 //We only expect a remote network identifier for managed connections 我们希望使用远程网络ID来管理连接 //if (ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled && NetworkIdentifier == ShortGuid.Empty) // throw new ConnectionSetupException("Remote network identifier should have been set by this point."); } } /// <summary> /// Note this connection as shutdown /// 标记连接已经关闭 /// </summary> internal void NoteConnectionShutdown() { lock (internalLocker) ConnectionState = ConnectionState.Shutdown; } /// <summary> /// Update the localEndPoint information for this connection /// 更新本地端点 /// </summary> /// <param name="localEndPoint"></param> internal void UpdateLocalEndPointInfo(EndPoint localEndPoint) { if (localEndPoint == null) throw new ArgumentNullException("localEndPoint", "localEndPoint may not be null."); lock (internalLocker) { hashCodeCacheSet = false; this.LocalEndPoint = localEndPoint; } } /// <summary> /// During a connection handShake we might be provided with more update information regarding endPoints, connectability and identifiers /// 当连接握手时 我们提供更多的更新信息 比如 端点 可连接性 和网络ID /// </summary> /// <param name="handshakeInfo"><see cref="ConnectionInfo"/> provided by remoteEndPoint during connection handshake. 在连接握手时,远端点提供的连接信息类</param> /// <param name="remoteEndPoint">The correct remoteEndPoint of this connection. 远端点</param> internal void UpdateInfoAfterRemoteHandshake(ConnectionInfo handshakeInfo, EndPoint remoteEndPoint) { lock (internalLocker) { NetworkIdentifierStr = handshakeInfo.NetworkIdentifier.ToString(); RemoteEndPoint = remoteEndPoint; //Not sure what this section was supposed to do 不确定这段是否可行 //For now we will uncomment and see if there was a reason during testing 根据测试 取消以下代码 因为其会带来一些bug //It certainly creates a bug at the moment //if (LocalEndPoint.GetType() == typeof(IPEndPoint) && handshakeInfo.LocalEndPoint.GetType() == typeof(IPEndPoint)) // ((IPEndPoint)LocalEndPoint).Address = ((IPEndPoint)handshakeInfo.LocalEndPoint).Address; //else // throw new NotImplementedException("UpdateInfoAfterRemoteHandshake not implemented for EndPoints of type " + LocalEndPoint.GetType()); IsConnectable = handshakeInfo.IsConnectable; } } /// <summary> /// Updates the last traffic time for this connection /// 更新连接的最近传输时间 /// </summary> internal void UpdateLastTrafficTime() { lock (internalLocker) lastTrafficTime = DateTime.Now; } /// <summary> /// Replaces the current networkIdentifier with that provided /// 替换网络ID /// </summary> /// <param name="networkIdentifier">The new networkIdentifier for this connectionInfo 新的网络ID</param> public void ResetNetworkIdentifer(ShortGuid networkIdentifier) { NetworkIdentifierStr = networkIdentifier.ToString(); } /// <summary> /// A connectionInfo object may be used across multiple connection sessions, i.e. due to a possible timeout. /// This method resets the state of the connectionInfo object so that it may be reused. /// 一个连接对象可以被多个连接会话使用 由于超时问题的存在 /// 此方法重置连接对象的状态使其可以被重新使用 /// </summary> internal void ResetConnectionInfo() { lock (internalLocker) { ConnectionState = ConnectionState.Undefined; } } /// <summary> /// Compares this <see cref="ConnectionInfo"/> object with obj and returns true if obj is ConnectionInfo and both /// the <see cref="NetworkIdentifier"/> and <see cref="RemoteEndPoint"/> match. /// 比较参数中的连接对象是否与当前连接对象相等 /// </summary> /// <param name="obj">The object to test of equality 测试相等的对象</param> /// <returns></returns> public override bool Equals(object obj) { lock (internalLocker) { var other = obj as ConnectionInfo; if (((object)other) == null) return false; else return this == other; } } /// <summary> /// Compares this <see cref="ConnectionInfo"/> object with other and returns true if both the <see cref="NetworkIdentifier"/> /// and <see cref="RemoteEndPoint"/> match. /// 比较参数中的对象是否与当前连接对象相等 /// </summary> /// <param name="other"></param> /// <returns></returns> public bool Equals(ConnectionInfo other) { lock (internalLocker) return this == other; } /// <summary> /// Returns left.Equals(right) /// 返回 left.Equals(right) /// </summary> /// <param name="left">左侧的连接对象 Left connectionInfo</param> /// <param name="right">右侧的连接对象 Right connectionInfo</param> /// <returns> 如果相等返回True True if both are equal, otherwise false</returns> public static bool operator ==(ConnectionInfo left, ConnectionInfo right) { if (((object)left) == ((object)right)) return true; else if (((object)left) == null || ((object)right) == null) return false; else { if (left.RemoteEndPoint != null && right.RemoteEndPoint != null && left.LocalEndPoint != null && right.LocalEndPoint != null) return (left.NetworkIdentifier.ToString() == right.NetworkIdentifier.ToString() && left.RemoteEndPoint.Equals(right.RemoteEndPoint) && left.LocalEndPoint.Equals(right.LocalEndPoint) && left.ApplicationLayerProtocol == right.ApplicationLayerProtocol); if (left.RemoteEndPoint != null && right.RemoteEndPoint != null) return (left.NetworkIdentifier.ToString() == right.NetworkIdentifier.ToString() && left.RemoteEndPoint.Equals(right.RemoteEndPoint) && left.ApplicationLayerProtocol == right.ApplicationLayerProtocol); else if (left.LocalEndPoint != null && right.LocalEndPoint != null) return (left.NetworkIdentifier.ToString() == right.NetworkIdentifier.ToString() && left.LocalEndPoint.Equals(right.LocalEndPoint) && left.ApplicationLayerProtocol == right.ApplicationLayerProtocol); else return (left.NetworkIdentifier.ToString() == right.NetworkIdentifier.ToString() && left.ApplicationLayerProtocol==right.ApplicationLayerProtocol); } } /// <summary> /// Returns !left.Equals(right) /// 返回连接对象是否不相等 /// </summary> /// <param name="left">Left connectionInfo</param> /// <param name="right">Right connectionInfo</param> /// <returns>True if both are different, otherwise false</returns> public static bool operator !=(ConnectionInfo left, ConnectionInfo right) { return !(left == right); } /// <summary> /// Returns NetworkIdentifier.GetHashCode() ^ RemoteEndPoint.GetHashCode(); /// 返回哈希码 /// </summary> /// <returns>The hashcode for this connection info</returns> public override int GetHashCode() { lock (internalLocker) { if (!hashCodeCacheSet) { if (RemoteEndPoint != null & LocalEndPoint != null) hashCodeCache = NetworkIdentifier.GetHashCode() ^ LocalEndPoint.GetHashCode() ^ RemoteEndPoint.GetHashCode() ^ (ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled ? 1 << 31 : 0); if (RemoteEndPoint != null) hashCodeCache = NetworkIdentifier.GetHashCode() ^ RemoteEndPoint.GetHashCode() ^ (ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled ? 1 << 31 : 0); else if (LocalEndPoint != null) hashCodeCache = NetworkIdentifier.GetHashCode() ^ LocalEndPoint.GetHashCode() ^ (ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled ? 1 << 31 : 0); else hashCodeCache = NetworkIdentifier.GetHashCode() ^ (ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled ? 1 << 31 : 0); hashCodeCacheSet = true; } return hashCodeCache; } } /// <summary> /// Returns a string containing suitable information about this connection /// 返回一个字符串 包含连接的状态信息 /// </summary> /// <returns>A string containing suitable information about this connection</returns> public override string ToString() { //Add a useful connection state identifier //添加一个有用的连接状态ID string connectionStateIdentifier; switch (ConnectionState) { case ConnectionState.Undefined: connectionStateIdentifier = "U"; break; case ConnectionState.Establishing: connectionStateIdentifier = "I"; break; case ConnectionState.Established: connectionStateIdentifier = "E"; break; case ConnectionState.Shutdown: connectionStateIdentifier = "S"; break; default: throw new Exception("Unexpected connection state."); } string returnString = "[" + ConnectionType.ToString() + "-" + (ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled ? "E" : "D") + "-" + connectionStateIdentifier + "] "; if (RemoteEndPoint != null && LocalEndPoint != null) returnString += LocalEndPoint.ToString() + " -> " + RemoteEndPoint.ToString(); else if (RemoteEndPoint != null) returnString += "Local -> " + RemoteEndPoint.ToString(); else if (LocalEndPoint != null) returnString += LocalEndPoint.ToString() + " " + (IsConnectable ? "Connectable" : "NotConnectable"); if (NetworkIdentifier != ShortGuid.Empty) returnString += " (" + NetworkIdentifier + ")"; return returnString.Trim(); } #region IExplicitlySerialize Members /// <inheritdoc /> /// 序列化ConnectionInfo V3版本在networkcomms的内核部分没有使用protobuf.net进行序列化 /// 这样使得基于networkcomms的程序可以很方便的更换序列化器. /// 把ConnectionInfo对象转化为二进制字节数据 public void Serialize(Stream outputStream) { List<byte[]> data = new List<byte[]>(); lock (internalLocker) { if (LocalEndPoint as IPEndPoint != null) { localEndPointAddressStr = LocalIPEndPoint.Address.ToString(); localEndPointPort = LocalIPEndPoint.Port; } #if NET4 || NET35 if (LocalEndPoint as InTheHand.Net.BluetoothEndPoint != null) { localEndPointAddressStr = LocalBTEndPoint.Address.ToString(); localEndPointPort = LocalBTEndPoint.Port; } #endif byte[] conTypeData = BitConverter.GetBytes((int)ConnectionType); data.Add(conTypeData); byte[] netIDData = Encoding.UTF8.GetBytes(NetworkIdentifierStr); byte[] netIDLengthData = BitConverter.GetBytes(netIDData.Length); data.Add(netIDLengthData); data.Add(netIDData); byte[] localEPAddreessData = Encoding.UTF8.GetBytes(localEndPointAddressStr); byte[] localEPAddreessLengthData = BitConverter.GetBytes(localEPAddreessData.Length); data.Add(localEPAddreessLengthData); data.Add(localEPAddreessData); byte[] localPortData = BitConverter.GetBytes(localEndPointPort); data.Add(localPortData); byte[] isConnectableData = BitConverter.GetBytes(IsConnectable); data.Add(isConnectableData); byte[] AppLayerEnabledData = BitConverter.GetBytes((int)ApplicationLayerProtocol); data.Add(AppLayerEnabledData); } foreach (byte[] datum in data) outputStream.Write(datum, 0, datum.Length); } /// <inheritdoc /> /// 反序列化 就是根据收到的内存流解析出ConnnectionInfo对象 public void Deserialize(System.IO.Stream inputStream) { byte[] conTypeData = new byte[sizeof(int)]; inputStream.Read(conTypeData, 0, conTypeData.Length); ConnectionType = (ConnectionType)BitConverter.ToInt32(conTypeData, 0); byte[] netIDLengthData = new byte[sizeof(int)]; inputStream.Read(netIDLengthData, 0, netIDLengthData.Length); byte[] netIDData = new byte[BitConverter.ToInt32(netIDLengthData, 0)]; inputStream.Read(netIDData, 0, netIDData.Length); NetworkIdentifierStr = new String(Encoding.UTF8.GetChars(netIDData)); byte[] localEPAddreessLengthData = new byte[sizeof(int)]; inputStream.Read(localEPAddreessLengthData, 0, sizeof(int)); byte[] localEPAddreessData = new byte[BitConverter.ToInt32(localEPAddreessLengthData, 0)]; inputStream.Read(localEPAddreessData, 0, localEPAddreessData.Length); localEndPointAddressStr = new String(Encoding.UTF8.GetChars(localEPAddreessData)); byte[] localPortData = new byte[sizeof(int)]; inputStream.Read(localPortData, 0, sizeof(int)); localEndPointPort = BitConverter.ToInt32(localPortData, 0); byte[] isConnectableData = new byte[sizeof(int)]; inputStream.Read(isConnectableData, 0, sizeof(bool)); IsConnectable = BitConverter.ToBoolean(isConnectableData, 0); byte[] AppLayerEnabledData = new byte[sizeof(int)]; inputStream.Read(AppLayerEnabledData, 0, sizeof(int)); ApplicationLayerProtocol = (ApplicationLayerProtocolStatus)BitConverter.ToInt32(AppLayerEnabledData, 0); #if NET4 || NET35 if (ConnectionType == ConnectionType.Bluetooth) { BluetoothAddress btAddress; if(!BluetoothAddress.TryParse(localEndPointAddressStr, out btAddress)) throw new ArgumentException("Failed to parse BluetoothAddress from localEndPointAddressStr", "localEndPointAddressStr"); LocalEndPoint = new BluetoothEndPoint(btAddress, BluetoothService.SerialPort, localEndPointPort); return; } #endif IPAddress ipAddress; if (!IPAddress.TryParse(localEndPointAddressStr, out ipAddress)) throw new ArgumentException("Failed to parse IPAddress from localEndPointAddressStr", "localEndPointAddressStr"); LocalEndPoint = new IPEndPoint(ipAddress, localEndPointPort); } /// <summary> /// Deserializes from a memory stream to a <see cref="ConnectionInfo"/> object /// </summary> /// <param name="ms">The memory stream containing the serialized <see cref="ConnectionInfo"/></param> /// <param name="result">The deserialized <see cref="ConnectionInfo"/></param> public static void Deserialize(MemoryStream ms, out ConnectionInfo result) { result = new ConnectionInfo(); result.Deserialize(ms); } #endregion }
该类实现了IExplicitlySerialize接口。
这是框架作者,从通讯内核中解耦protobuf序列化器所作的工作。实现了这个接口,可以使用显式的方法对ConnectionInfo类进行序列化,是的通信框架可以脱离Protobuf而进行工作。
当然,框架中还有一些别的类也需要实现这个接口。
以上是关于介绍开源的.net通信框架NetworkComms框架 源码分析ConnectionInfo的主要内容,如果未能解决你的问题,请参考以下文章
介绍开源的.net通信框架NetworkComms框架 源码分析ConnectionState
介绍开源的.net通信框架NetworkComms框架之六 x509证书通信
介绍开源的.net通信框架NetworkComms框架之九 合并DLL
介绍开源的.net通信框架NetworkComms框架 源码分析ConnectionInfo