介绍开源的.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:
                    );
                    break;
                case AddressFamily.InterNetworkV6:
                    );
                    break;
#if NET4 || NET35
                :
                    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:
                    );
                    break;
                case AddressFamily.InterNetworkV6:
                    );
                    break;
#if NET4 || NET35
                :
                    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:
                    );
                    break;
                case AddressFamily.InterNetworkV6:
                    );
                    break;
#if NET4 || NET35
                :
                    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:
                    );
                    break;
                case AddressFamily.InterNetworkV6:
                    );
                    break;
#if NET4 || NET35
                :
                    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:
                    );
                    break;
                case AddressFamily.InterNetworkV6:
                    );
                    break;
#if NET4 || NET35
                :
                    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:
                    );
                    break;
                case AddressFamily.InterNetworkV6:
                    );
                    break;
#if NET4 || NET35
                :
                    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 ?  <<  : );
                    if (RemoteEndPoint != null)
                        hashCodeCache = NetworkIdentifier.GetHashCode() ^ RemoteEndPoint.GetHashCode() ^ (ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled ?  <<  : );
                    else if (LocalEndPoint != null)
                        hashCodeCache = NetworkIdentifier.GetHashCode() ^ LocalEndPoint.GetHashCode() ^ (ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled ?  <<  : );
                    else
                        hashCodeCache = NetworkIdentifier.GetHashCode() ^ (ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled ?  <<  : );

                    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, , datum.Length);
        }

        /// <inheritdoc />
        /// 反序列化   就是根据收到的内存流解析出ConnnectionInfo对象
        public void Deserialize(System.IO.Stream inputStream)
        {
            , conTypeData.Length); 

            ConnectionType = (ConnectionType)BitConverter.ToInt32(conTypeData, );

            , netIDLengthData.Length);
            )]; inputStream.Read(netIDData, , netIDData.Length); 

            NetworkIdentifierStr = new String(Encoding.UTF8.GetChars(netIDData));

            , sizeof(int));
            )]; inputStream.Read(localEPAddreessData, , localEPAddreessData.Length); 

            localEndPointAddressStr = new String(Encoding.UTF8.GetChars(localEPAddreessData));

            , sizeof(int));

            localEndPointPort = BitConverter.ToInt32(localPortData, );

            , sizeof(bool));

            IsConnectable = BitConverter.ToBoolean(isConnectableData, );

            , sizeof(int));

            ApplicationLayerProtocol = (ApplicationLayerProtocolStatus)BitConverter.ToInt32(AppLayerEnabledData, );

#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而进行工作。

当然,框架中还有一些别的类也需要实现这个接口。

上一篇:【Asphyre引擎】Asphyre时隔3年,更名为PXL,全平台支持!


下一篇:[Angular 2] *ngFor with index