Connection类之ConnectionCreate.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>
        public ConnectionInfo ConnectionInfo { get; protected set; }

       
       
        /// 一个 manualResetEvent信号 用来处理连接的创建 setup
        
        protected ManualResetEvent connectionSetupWait = new ManualResetEvent(false);
        /// <summary>
        /// 一个 manualResetEvent信号 用来处理连接的创建  establish.
        /// </summary>
        protected ManualResetEvent connectionEstablishWait = new ManualResetEvent(false);

        /// <summary> 
        /// 连接创建是否异常
        /// </summary>
        protected bool connectionSetupException = false;
        /// <summary>
        /// 连接床架异常相关的信息
        /// </summary>
        protected string connectionSetupExceptionStr = "";

        /// <summary>
        ///创建一个连接对象
        /// </summary>
        /// <param name="connectionInfo">连接信息类</param>
        /// <param name="defaultSendReceiveOptions">默认的收发参数</param>
        protected Connection(ConnectionInfo connectionInfo, SendReceiveOptions defaultSendReceiveOptions)
        {
            //创建一个方差类 这个是数学模型
            SendTimesMSPerKBCache = new CommsMath();
            //默认的数据缓冲区大小
            dataBuffer = new byte[NetworkComms.ReceiveBufferSizeBytes];
            //实例化一个数据包创建器
            //PacketBuilder用来保存连接上收到的二进制数据
            //他的模型是这样的,连接上收到的第一个字节中的数据,对应的是数据包包头的长度,根据第一个字节中的数据,解析出数据包包头,
            //然后根据数据包包头中的信息,信息包括数据包长度,再解析出数据包,然后把数据包交给相应的处理器进行处理
            packetBuilder = new PacketBuilder();

        
            //初始化一个顺序号 之后每发送一个数据包顺序后都加1 所以没有包的顺序号都是唯一的
            packetSequenceCounter = Interlocked.Increment(ref NetworkComms.totalPacketSendCount);

            ConnectionInfo = connectionInfo;

            if (defaultSendReceiveOptions != null)
                ConnectionDefaultSendReceiveOptions = defaultSendReceiveOptions;
            else
                //如果没有默认的收发参数 则使用NetworkComms静态类中的默认收发参数
                //默认收发参数使用protobuf作为序列化器,没有启用加密和压缩处理器
                ConnectionDefaultSendReceiveOptions = NetworkComms.DefaultSendReceiveOptions;

            if (NetworkComms.commsShutdown) throw new ConnectionSetupException("Attempting to create new connection after global comms shutdown has been initiated.");

            if (ConnectionInfo.ConnectionType == ConnectionType.Undefined || ConnectionInfo.RemoteEndPoint == null)
                throw new ConnectionSetupException("ConnectionType and RemoteEndPoint must be defined within provided ConnectionInfo.");

            //If a connection already exists with this info then we can throw an exception here to prevent duplicates
            if (NetworkComms.ConnectionExists(connectionInfo.RemoteEndPoint, connectionInfo.ConnectionType))
                throw new ConnectionSetupException("A connection already exists with " + ConnectionInfo);

            //添加连接到NetworkComms静态类中
            //比如说服务器的话,会把监听到的连接都添加一个引用到NetworkComms静态类中
            //如果某个连接断开了,networkComms静态类中,也会相应的删除这个连接。
            NetworkComms.AddConnectionByReferenceEndPoint(this);
        }

        /// <summary>
        ///创建这个连接
        /// </summary>
        public void EstablishConnection()
        {
            try
            {
                bool connectionAlreadyEstablishing = false;
                lock (delegateLocker)
                {
                    if (ConnectionInfo.ConnectionState == ConnectionState.Established) return;
                    else if (ConnectionInfo.ConnectionState == ConnectionState.Shutdown) throw new ConnectionSetupException("Attempting to re-establish a closed connection. Please create a new connection instead.");
                    else if (ConnectionInfo.ConnectionState == ConnectionState.Establishing)
                        connectionAlreadyEstablishing = true;
                    else
                        ConnectionInfo.NoteStartConnectionEstablish();
                }

                if (connectionAlreadyEstablishing)
                {
                    if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("Waiting for connection with " + ConnectionInfo + " to be established.");
                    if (!WaitForConnectionEstablish(NetworkComms.ConnectionEstablishTimeoutMS))
                        throw new ConnectionSetupException("Timeout waiting for connection to be succesfully established.");
                }
                else
                {
                    if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("Establishing new connection with " + ConnectionInfo);

                    //这是个virtual方法,具体工作交给子类去做,TCPConnection类负责建立Tcp连接 UDPConnection类负责建UDP连接
                    EstablishConnectionSpecific();

                    if (ConnectionInfo.ConnectionState == ConnectionState.Shutdown) throw new ConnectionSetupException("Connection was closed during establish handshake.");

                    if (ConnectionInfo.NetworkIdentifier == ShortGuid.Empty)
                        throw new ConnectionSetupException("Remote network identifier should have been set by this point.");

                    //Once the above has been done the last step is to allow other threads to use the connection
                    ConnectionInfo.NoteCompleteConnectionEstablish();
                    NetworkComms.AddConnectionReferenceByIdentifier(this);
                    connectionEstablishWait.Set();

                    if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... connection succesfully established with " + ConnectionInfo);
                }
            }
            catch (SocketException e)
            {
                //If anything goes wrong we close the connection.
                CloseConnection(true, 43);
                throw new ConnectionSetupException(e.ToString());
            }
            catch (Exception ex)
            {
                //If anything goes wrong we close the connection.
                CloseConnection(true, 44);

                //For some odd reason not all SocketExceptions get caught above, so another check here
                if (ex.GetBaseException().GetType() == typeof(SocketException))
                    throw new ConnectionSetupException(ex.ToString());
                else
                    throw;
            }
        }

        /// <summary>
        /// Any connection type specific establish tasks. Base should be called to trigger connection establish delegates
        /// </summary>
        protected virtual void EstablishConnectionSpecific()
        {
            //Call asynchronous connection establish delegates here
            if (NetworkComms.globalConnectionEstablishDelegatesAsync != null)
            {
                NetworkComms.CommsThreadPool.EnqueueItem(QueueItemPriority.Normal, new WaitCallback((obj) =>
                {
                    Connection connectionParam = obj as Connection;
                    NetworkComms.globalConnectionEstablishDelegatesAsync(connectionParam);
                }), this);
            }

            //Call synchronous connection establish delegates here
            if (NetworkComms.globalConnectionEstablishDelegatesSync != null)
                NetworkComms.globalConnectionEstablishDelegatesSync(this);
        }

        /// <summary>
        /// Return true if the connection is established within the provided timeout, otherwise false
        /// </summary>
        /// <param name="waitTimeoutMS">Wait time in milliseconds before returning</param>
        /// <returns>True if the wait was triggered, false otherwise after the provided timeout.</returns>
        protected bool WaitForConnectionEstablish(int waitTimeoutMS)
        {
            if (ConnectionInfo.ConnectionState == ConnectionState.Established)
                return true;
            else
            {
                if (NetworkComms.LoggingEnabled)
                    NetworkComms.Logger.Trace("Waiting for new connection to be succesfully established before continuing with " + ConnectionInfo);

                if (ConnectionInfo.ConnectionState == ConnectionState.Shutdown)
                    throw new ConnectionShutdownException("Attempted to wait for connection establish on a connection that is already shutdown.");

                return connectionSetupWait.WaitOne(waitTimeoutMS);
            }
        }

        /// <summary>
        /// Handle an incoming ConnectionSetup packet type
        /// </summary>
        /// <param name="packetDataSection">Serialised handshake data</param>
        internal void ConnectionSetupHandler(MemoryStream packetDataSection)
        {
            //We should never be trying to handshake an established connection
            ConnectionInfo remoteConnectionInfo = NetworkComms.InternalFixedSendReceiveOptions.DataSerializer.DeserialiseDataObject<ConnectionInfo>(packetDataSection,
                NetworkComms.InternalFixedSendReceiveOptions.DataProcessors, NetworkComms.InternalFixedSendReceiveOptions.Options);

            if (ConnectionInfo.ConnectionType != remoteConnectionInfo.ConnectionType)
            {
                connectionSetupException = true;
                connectionSetupExceptionStr = "Remote connectionInfo provided connectionType did not match expected connection type.";
            }
            else
            {
                //We use the following bool to track a possible existing connection which needs closing
                bool possibleClashConnectionWithPeer_ByEndPoint = false;
                Connection existingConnection = null;

                //We first try to establish everything within this lock in one go
                //If we can't quite complete the establish we have to come out of the lock at try to sort the problem
                bool connectionEstablishedSuccess = ConnectionSetupHandlerFinal(remoteConnectionInfo, ref possibleClashConnectionWithPeer_ByEndPoint, ref existingConnection);

                //If we were not succesfull at establishing the connection we need to sort it out!
                if (!connectionEstablishedSuccess && !connectionSetupException)
                {
                    if (existingConnection == null) throw new Exception("Connection establish issues and existingConnection was left as null.");

                    if (possibleClashConnectionWithPeer_ByEndPoint)
                    {
                        //If we have a clash by endPoint we test the existing connection
                        if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Debug("Existing connection with " + ConnectionInfo + ". Testing existing connection.");
                        if (existingConnection.ConnectionAlive(1000))
                        {
                            //If the existing connection comes back as alive we don't allow this one to go any further
                            //This might happen if two peers try to connect to each other at the same time
                            connectionSetupException = true;
                            connectionSetupExceptionStr = " ... existing live connection at provided end point for this connection (" + ConnectionInfo + "), there should be no need for a second.";
                        }
                    }

                    //We only try again if we did not log an exception
                    if (!connectionSetupException)
                    {
                        //Once we have tried to sort the problem we can try to finish the establish one last time
                        connectionEstablishedSuccess = ConnectionSetupHandlerFinal(remoteConnectionInfo, ref possibleClashConnectionWithPeer_ByEndPoint, ref existingConnection);

                        //If we still failed then that's it for this establish
                        if (!connectionEstablishedSuccess && !connectionSetupException)
                        {
                            connectionSetupException = true;
                            connectionSetupExceptionStr = "Attempted to establish conneciton with " + ConnectionInfo + ", but due to an existing connection this was not possible.";
                        }
                    }
                }
            }

            //Trigger any setup waits
            connectionSetupWait.Set();
        }

        /// <summary>
        /// Attempts to complete the connection establish with a minimum of locking to prevent possible deadlocking
        /// </summary>
        /// <param name="remoteConnectionInfo"><see cref="ConnectionInfo"/> corresponding with remoteEndPoint</param>
        /// <param name="possibleClashConnectionWithPeer_ByEndPoint">True if a connection already exists with provided remoteEndPoint</param>
        /// <param name="existingConnection">A reference to an existing connection if it exists</param>
        /// <returns>True if connection is successfully setup, otherwise false</returns>
        private bool ConnectionSetupHandlerFinal(ConnectionInfo remoteConnectionInfo, ref bool possibleClashConnectionWithPeer_ByEndPoint, ref Connection existingConnection)
        {
            lock (NetworkComms.globalDictAndDelegateLocker)
            {
                Connection connectionByEndPoint = NetworkComms.GetExistingConnection(ConnectionInfo.RemoteEndPoint, ConnectionInfo.ConnectionType);

                //If we no longer have the original endPoint reference (set in the constructor) then the connection must have been closed already
                if (connectionByEndPoint == null)
                {
                    connectionSetupException = true;
                    connectionSetupExceptionStr = "Connection setup received after connection closure with " + ConnectionInfo;
                }
                else
                {
                    //We need to check for a possible GUID clash
                    //Probability of a clash is approx 0.1% if 1E19 connection are maintained simultaneously (This many connections has not be tested ;))
                    //but hey, we live in a crazy world!
                    if (remoteConnectionInfo.NetworkIdentifier == NetworkComms.NetworkIdentifier)
                    {
                        connectionSetupException = true;
                        connectionSetupExceptionStr = "Remote peer has same network idendifier to local, " + remoteConnectionInfo.NetworkIdentifier + ". A real duplication is vanishingly improbable so this exception has probably been thrown because the local and remote application are the same.";
                    }
                    else if (connectionByEndPoint != this)
                    {
                        possibleClashConnectionWithPeer_ByEndPoint = true;
                        existingConnection = connectionByEndPoint;
                    }
                    else
                    {
                        //Update the connection info
                        //We never change the this.ConnectionInfo.RemoteEndPoint.Address as there might be NAT involved
                        //We may update the port however
                        IPEndPoint newRemoteIPEndPoint = new IPEndPoint(this.ConnectionInfo.RemoteEndPoint.Address, remoteConnectionInfo.LocalEndPoint.Port);
                        NetworkComms.UpdateConnectionReferenceByEndPoint(this, newRemoteIPEndPoint);

                        ConnectionInfo.UpdateInfoAfterRemoteHandshake(remoteConnectionInfo, newRemoteIPEndPoint);

                        return true;
                    }
                }
            }

            return false;
        }

        /// <summary>
        /// Returns ConnectionInfo.ToString
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return ConnectionInfo.ToString();
        }
    }
}

 

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

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

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

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

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

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

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

 

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

转载于:https://my.oschina.net/networkcomms/blog/382000

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值