原文网址: http://www.cnblogs.com/csdev

Networkcomms 是一款C# 语言编写的TCP/UDP通信框架  作者是英国人  以前是收费的 目前作者已经开源  许可是:Apache License v2

开源地址是:https://github.com/MarcFletcher/NetworkComms.Net

 public abstract partial class Connection : IDisposable
    {
        /// <summary>
        /// Lockers for maintaining thread safe operation
        /// 同步锁
        /// </summary>
        protected object sendLocker = new object();

        /// <summary>
        /// A NetworkComms.Net math object for tracking send times. Used to prevent send deadlocks.
        /// Initialised at 1000 milliseconds per KB write speed, corresponding with 1KB / second.
        /// 一个数学类 用来跟踪发送事件 以阻止死锁显现的发生
        /// 初始化为  1KB每秒的发送速度
        /// </summary>
        protected CommsMath SendTimesMSPerKBCache;

        /// <summary>
        /// A counter which is incremented during every a send. The current value is included in the header of all sent packets.
        /// 数据包的顺序号 一个递增计数器,在每一个发送数据包的报头中会包含。
        /// </summary>
        protected long packetSequenceCounter;

        /// <summary>
        /// Maintains a list of sent packets for the purpose of confirmation and possible resends.
        /// 同步锁
        /// </summary>
        object sentPacketsLocker = new object();
        //已发送过的数据包存放在此处 以备对方没有收到需要重发   超过一定的时间会删除 只保留一定时间内的数据包
        Dictionary<string, SentPacket> sentPackets = new Dictionary<string, SentPacket>();

        /// <summary>
        /// Send bytes on an unmanaged connection
        /// 在“未托管”的连接上发送字节
        /// </summary>
        /// <param name="bytesToSend">The bytes to send</param>
        public void SendUnmanagedBytes(byte[] bytesToSend)
        {
            if (ConnectionInfo.ApplicationLayerProtocol != ApplicationLayerProtocolStatus.Disabled)
                throw new CommunicationException("Attempted to send unmanaged bytes on a managed connection. This method should only be used on connections which have the ApplicationLayerProtocol disabled.");

            SendObject<byte[]>(Enum.GetName(typeof(ReservedPacketType), ReservedPacketType.Unmanaged), bytesToSend);
        }

        /// <summary>
        /// Send an object using the connection default <see cref="SendReceiveOptions"/>
        /// 发送数据使用默认的收发参数
        /// </summary>
        /// <param name="sendingPacketType">消息类型  The sending packet type</param>
        /// <param name="objectToSend">发送的对象  The object to send</param>
        public void SendObject<sendObjectType>(string sendingPacketType, sendObjectType objectToSend)
        {
            SendObject(sendingPacketType, objectToSend, ConnectionDefaultSendReceiveOptions);
        }

        /// <summary>
        /// Send an object using the connection default <see cref="SendReceiveOptions"/>
        /// 发送数据使用默认的收发参数
        /// </summary>
        /// <param name="sendingPacketType">消息类型  The sending packet type</param>
        /// <param name="objectToSend">发送的对象 The object to send</param>
        /// <param name="packetSequenceNumber">发送的数据包的顺序号 The sequence number of the packet sent</param>
        public void SendObject<sendObjectType>(string sendingPacketType, sendObjectType objectToSend, out long packetSequenceNumber)
        {
            SendObject(sendingPacketType, objectToSend, ConnectionDefaultSendReceiveOptions, out packetSequenceNumber);
        }

        /// <summary>
        /// Send an object using the provided SendReceiveOptions
        /// 用参数中指定的收发参数  发送数据包
        /// </summary>
        /// <param name="sendingPacketType">消息类型  The packet type to use for send</param>
        /// <param name="objectToSend">发送的对象  The object to send</param>
        /// <param name="options">收发参数  Send specific <see cref="SendReceiveOptions"/></param>
        public void SendObject<sendObjectType>(string sendingPacketType, sendObjectType objectToSend, SendReceiveOptions options)
        {
            //Check to see if we already have a packet
            //检查要发送的数据本身是否为数据包
            Packet objectToSendAsPacket = objectToSend as Packet;
            if (objectToSendAsPacket == null)
            {
                using (Packet sendPacket = new Packet(sendingPacketType, objectToSend, options))
                    SendPacket<sendObjectType>(sendPacket);
            }
            else
            {
                if (objectToSendAsPacket.PacketHeader.PacketType != sendingPacketType)
                    throw new ArgumentException("Unable to send object of type Packet if the PacketHeader.PacketType and sendingPacketType do not match.");

                SendPacket<sendObjectType>(objectToSendAsPacket);
            }
        }

        /// <summary>
        /// Send an object using the provided SendReceiveOptions
        /// 用参数中指定的收发参数  发送数据包
        /// </summary>
        /// <param name="sendingPacketType">消息类型 The packet type to use for send</param>
        /// <param name="objectToSend">发送的对象 The object to send</param>
        /// <param name="options">收发参数  Send specific <see cref="SendReceiveOptions"/></param>
        /// <param name="packetSequenceNumber">顺序号  The sequence number of the packet sent</param>
        public void SendObject<sendObjectType>(string sendingPacketType, sendObjectType objectToSend, SendReceiveOptions options, out long packetSequenceNumber)
        {
            Packet objectToSendAsPacket = objectToSend as Packet;
            if (objectToSendAsPacket == null)
            {
                using (Packet sendPacket = new Packet(sendingPacketType, objectToSend, options))
                    SendPacket<sendObjectType>(sendPacket, out packetSequenceNumber);
            }
            else
            {
                if (objectToSendAsPacket.PacketHeader.PacketType != sendingPacketType)
                    throw new ArgumentException("Unable to send object of type Packet if the PacketHeader.PacketType and sendingPacketType do not match.");

                SendPacket<sendObjectType>(objectToSendAsPacket, out packetSequenceNumber);
            }
        }

        /// <summary>
        /// Send an empty packet using the provided packetType. Useful for signalling.
        /// 根据指定的消息类型 发送一个空数据包 发送信号时有用
        /// </summary>
        /// <param name="sendingPacketType">The sending packet type</param>
        public void SendObject(string sendingPacketType)
        {
            SendObject<object>(sendingPacketType, null);
        }

        /// <summary>
        /// Send an empty packet using the provided packetType. Useful for signalling.
        /// 根据指定的消息类型 发送一个空数据包 发送信号时有用
        /// </summary>
        /// <param name="sendingPacketType">消息类型 The sending packet type</param>
        /// <param name="packetSequenceNumber">顺序号  The sequence number of the packet sent</param>
        public void SendObject(string sendingPacketType, out long packetSequenceNumber)
        {
            SendObject<object>(sendingPacketType, null, ConnectionDefaultSendReceiveOptions, out packetSequenceNumber);
        }

        /// <summary>
        /// Send an object using the connection default <see cref="SendReceiveOptions"/> and wait for a returned object
        /// again using default <see cref="SendReceiveOptions"/>.
        /// 发送并接收数据 (同步方法)
        /// </summary>
        /// <typeparam name="sendObjectType">发送的类的类型 The sending object type, i.e. string, int[], etc</typeparam>
        /// <typeparam name="returnObjectType">返回的类的类型  The type of return object</typeparam>
        /// <param name="sendingPacketTypeStr">发送的消息类型The sending packet type</param>
        /// <param name="expectedReturnPacketTypeStr">预期返回的消息类型The packet type which will be used for the reply</param>
        /// <param name="returnPacketTimeOutMilliSeconds">消息返回的超时时间  A timeout in milliseconds after which if not reply is received
        /// will throw an ExpectedReturnTimeoutException.</param>
        /// <param name="sendObject">发送的对象  The object to send</param>
        /// <returns>返回的对象  The requested return object</returns>
        public returnObjectType SendReceiveObject<sendObjectType, returnObjectType>(string sendingPacketTypeStr, string expectedReturnPacketTypeStr, int returnPacketTimeOutMilliSeconds, sendObjectType sendObject)
        {
            return SendReceiveObject<sendObjectType, returnObjectType>(sendingPacketTypeStr, expectedReturnPacketTypeStr, returnPacketTimeOutMilliSeconds, sendObject, null, null);
        }

        /// <summary>
        /// Send an object using the connection default <see cref="SendReceiveOptions"/> and wait for a returned object again
        /// using default <see cref="SendReceiveOptions"/>.
        /// 发送并接收数据 (同步方法)
        /// </summary>
        /// <typeparam name="sendObjectType">发送的类的类型 The sending object type, i.e. string, int[], etc</typeparam>
        /// <typeparam name="returnObjectType">返回的类的类型  The type of return object</typeparam>
        /// <param name="sendingPacketTypeStr">发送的消息类型  The sending packet type</param>
        /// <param name="expectedReturnPacketTypeStr">预期返回的消息类型  The packet type which will be used for the reply</param>
        /// <param name="returnPacketTimeOutMilliSeconds">消息返回的超时时间  A timeout in milliseconds after which if not reply is received will
        /// throw an ExpectedReturnTimeoutException.</param>
        /// <param name="sendObject">发送的对象  The object to send</param>
        /// <param name="sentPacketSequenceNumber">包的顺序号  The sequence number of the packet sent</param>
        /// <returns>返回的对象  The requested return object</returns>
        public returnObjectType SendReceiveObject<sendObjectType, returnObjectType>(string sendingPacketTypeStr, string expectedReturnPacketTypeStr, int returnPacketTimeOutMilliSeconds, sendObjectType sendObject, out long sentPacketSequenceNumber)
        {
            return SendReceiveObject<sendObjectType, returnObjectType>(sendingPacketTypeStr, expectedReturnPacketTypeStr, returnPacketTimeOutMilliSeconds, sendObject, null, null, out sentPacketSequenceNumber);
        }

        /// <summary>
        /// Send an object using the provided <see cref="SendReceiveOptions"/> and wait for a returned object using provided
        /// 发送并接收数据 (同步方法)
        /// </summary>
        /// <typeparam name="sendObjectType">发送的类的类型 The sending object type, i.e. string, int[], etc</typeparam>
        /// <typeparam name="returnObjectType">返回的类的类型  The type of return object</typeparam>
        /// <param name="sendingPacketTypeStr">发送的消息类型  The sending packet type</param>
        /// <param name="expectedReturnPacketTypeStr">预期返回的消息类型  The packet type which will be used for the reply</param>
        /// <param name="returnPacketTimeOutMilliSeconds">消息返回的超时时间  A timeout in milliseconds after which if not reply is received will
        /// throw an ExpectedReturnTimeoutException.</param>
        /// <param name="sendObject">发送的对象  The object to send</param>
        /// <param name="sendOptions">发送时的收发参数  SendReceiveOptions to use when sending</param>
        /// <param name="receiveOptions">接收时的收发参数  SendReceiveOptions used when receiving the return object</param>
        /// <returns>The requested return object</returns>
        public returnObjectType SendReceiveObject<sendObjectType, returnObjectType>(string sendingPacketTypeStr, string expectedReturnPacketTypeStr, int returnPacketTimeOutMilliSeconds, sendObjectType sendObject, SendReceiveOptions sendOptions, SendReceiveOptions receiveOptions)
        {
            long sentPacketSequenceNumber;
            return SendReceiveObject<sendObjectType, returnObjectType>(sendingPacketTypeStr, expectedReturnPacketTypeStr, returnPacketTimeOutMilliSeconds, sendObject, sendOptions, receiveOptions, out sentPacketSequenceNumber);
        }

        /// <summary>
        /// Send an object using the provided <see cref="SendReceiveOptions"/> and wait for a returned object using provided
        /// 发送并接收数据 (同步方法)
        /// </summary>
        /// <typeparam name="sendObjectType">发送的类的类型 The sending object type, i.e. string, int[], etc</typeparam>
        /// <typeparam name="returnObjectType">返回的类的类型  The type of return object</typeparam>
        /// <param name="sendingPacketTypeStr">发送的消息类型  The sending packet type</param>
        /// <param name="expectedReturnPacketTypeStr">预期返回的消息类型  The packet type which will be used for the reply</param>
        /// <param name="returnPacketTimeOutMilliSeconds">消息返回的超时时间  A timeout in milliseconds after which if not reply is received will
        /// throw an ExpectedReturnTimeoutException.</param>
        /// <param name="sendObject">发送的对象  The object to send</param>
        /// <param name="sendOptions">发送时的收发参数  SendReceiveOptions to use when sending</param>
        /// <param name="receiveOptions">接收时的收发参数  SendReceiveOptions used when receiving the return object</param>
        /// <param name="sentPacketSequenceNumber">数据包的顺序号The sequence number of the packet sent</param>
        /// <returns>The requested return object</returns>
        public returnObjectType SendReceiveObject<sendObjectType, returnObjectType>(string sendingPacketTypeStr, string expectedReturnPacketTypeStr, int returnPacketTimeOutMilliSeconds, sendObjectType sendObject, SendReceiveOptions sendOptions, SendReceiveOptions receiveOptions, out long sentPacketSequenceNumber)
        {
            if (sendingPacketTypeStr == expectedReturnPacketTypeStr)
                throw new ArgumentException("The provided sendingPacketTypeStr and expectedReturnPacketTypeStr parameters must be different.");

            returnObjectType returnObject = default(returnObjectType);

            bool remotePeerDisconnectedDuringWait = false;
            AutoResetEvent returnWaitSignal = new AutoResetEvent(false);

            #region SendReceiveDelegate
            NetworkComms.PacketHandlerCallBackDelegate<returnObjectType> SendReceiveDelegate = (packetHeader, sourceConnection, incomingObject) =>
            {
                returnObject = incomingObject;
                returnWaitSignal.Set();
            };

            //We use the following delegate to quickly force a response timeout if the remote end disconnects
            //如果远端掉线 我们使用下面的委托马上触发等待超时
            NetworkComms.ConnectionEstablishShutdownDelegate SendReceiveShutDownDelegate = (sourceConnection) =>
            {
                remotePeerDisconnectedDuringWait = true;
                returnObject = default(returnObjectType);
                returnWaitSignal.Set();
            };
            #endregion

            if (sendOptions == null) sendOptions = ConnectionDefaultSendReceiveOptions;
            if (receiveOptions == null) receiveOptions = ConnectionDefaultSendReceiveOptions;

            AppendShutdownHandler(SendReceiveShutDownDelegate);
            AppendIncomingPacketHandler(expectedReturnPacketTypeStr, SendReceiveDelegate, receiveOptions);

            //Check to see if we already have a packet
            //检测我们是否已经获得数据包
            Packet sendObjectAsPacket = sendObject as Packet;
            if (sendObjectAsPacket == null)
            {
                using (Packet sendPacket = new Packet(sendingPacketTypeStr, expectedReturnPacketTypeStr, sendObject, sendOptions))
                    SendPacket<sendObjectType>(sendPacket, out sentPacketSequenceNumber);
            }
            else
            {
                if (sendObjectAsPacket.PacketHeader.PacketType != sendingPacketTypeStr)
                    throw new ArgumentException("Unable to send object of type Packet if the PacketHeader.PacketType and sendingPacketType do not match.");

                SendPacket<sendObjectType>(sendObjectAsPacket, out sentPacketSequenceNumber);
            }

            //We wait for the return data here
            //等待返回的数据
#if NET2
            if (!returnWaitSignal.WaitOne(returnPacketTimeOutMilliSeconds, false))
#else
            if (!returnWaitSignal.WaitOne(returnPacketTimeOutMilliSeconds))
#endif
            {
                RemoveIncomingPacketHandler(expectedReturnPacketTypeStr, SendReceiveDelegate);
                throw new ExpectedReturnTimeoutException("Timeout occurred after " + returnPacketTimeOutMilliSeconds.ToString() + "ms waiting for response packet of type '" + expectedReturnPacketTypeStr + "'.");
            }

            RemoveIncomingPacketHandler(expectedReturnPacketTypeStr, SendReceiveDelegate);
            RemoveShutdownHandler(SendReceiveShutDownDelegate);

            if (remotePeerDisconnectedDuringWait)
                throw new ConnectionShutdownException("Remote end closed connection before data was successfully returned.");
            else
                return returnObject;
        }

        /// <summary>
        /// Send an empty packet using the connection default <see cref="SendReceiveOptions"/> and wait for a returned object again
        /// using default <see cref="SendReceiveOptions"/>. Useful to request an object when there is no need to send anything.
        /// 发送空的数据包给对方 使用默认的收发参数 并等待返回的数据包
        /// 当我们从对方获取某个对象,但不需要发送对象给对方时使用
        /// </summary>
        /// <typeparam name="returnObjectType">返回的对象的类型The type of return object</typeparam>
        /// <param name="sendingPacketTypeStr">消息类型 The sending packet type</param>
        /// <param name="expectedReturnPacketTypeStr">期待返回的消息类型  The packet type which will be used for the reply</param>
        /// <param name="returnPacketTimeOutMilliSeconds">超时时间  A timeout in milliseconds after which if not reply is received will throw
        /// an ExpectedReturnTimeoutException.</param>
        /// <returns></returns>
        public returnObjectType SendReceiveObject<returnObjectType>(string sendingPacketTypeStr, string expectedReturnPacketTypeStr, int returnPacketTimeOutMilliSeconds)
        {
            return SendReceiveObject<object, returnObjectType>(sendingPacketTypeStr, expectedReturnPacketTypeStr, returnPacketTimeOutMilliSeconds, null, null, null);
        }

        /// <summary>
        /// Send an empty packet using the connection default <see cref="SendReceiveOptions"/> and wait for a returned object again using default <see cref="SendReceiveOptions"/>. Usefull to request an object when there is no need to send anything.
        /// 发送空的数据包给对方 使用默认的收发参数 并等待返回的数据包
        /// 当我们从对方获取某个对象,但不需要发送对象给对方时使用
        /// </summary>
        /// <typeparam name="returnObjectType">返回的对象的类型 The type of return object</typeparam>
        /// <param name="sendingPacketTypeStr">消息类型 The sending packet type</param>
        /// <param name="expectedReturnPacketTypeStr">期待返回的消息类型 The packet type which will be used for the reply</param>
        /// <param name="returnPacketTimeOutMilliSeconds">超时时间 A timeout in milliseconds after which if not reply is received will throw an ExpectedReturnTimeoutException.</param>
        /// <param name="sentPacketSequenceNumber">包的顺序号  The sequence number of the packet sent</param>
        /// <returns></returns>
        public returnObjectType SendReceiveObject<returnObjectType>(string sendingPacketTypeStr, string expectedReturnPacketTypeStr, int returnPacketTimeOutMilliSeconds, out long sentPacketSequenceNumber)
        {
            return SendReceiveObject<object, returnObjectType>(sendingPacketTypeStr, expectedReturnPacketTypeStr, returnPacketTimeOutMilliSeconds, null, null, null, out sentPacketSequenceNumber);
        }

        /// <summary>
        /// Closes the connection and trigger any associated shutdown delegates.
        /// 关闭连接并触发相关的委托
        /// </summary>
        /// <param name="closeDueToError">关闭 是否是由于错误  Closing a connection due an error possibly requires a few extra steps.</param>
        /// <param name="logLocation">可选的调试参数  Optional debug parameter.</param>
        )
        {
            try
            {
                if (NetworkComms.LoggingEnabled)
                {
                    if (closeDueToError)
                        NetworkComms.Logger.Debug("Closing connection with " + ConnectionInfo + " due to error from [" + logLocation.ToString() + "].");
                    else
                        NetworkComms.Logger.Debug("Closing connection with " + ConnectionInfo + " from [" + logLocation.ToString() + "].");
                }

                ConnectionInfo.NoteConnectionShutdown();

                //Set possible error cases 设置可能的错误情况

                if (closeDueToError)
                {
                    connectionSetupException = true;
                    connectionSetupExceptionStr = "Connection was closed during setup from [" + logLocation.ToString() + "].";
                }

                //Ensure we are not waiting for a connection to be established if we have died due to error
                //给connectionSetupWait信号 确保连接关闭后  系统不再等待连接的创建
                connectionSetupWait.Set();

                //Call any connection specific close requirements
                //关闭连接的具体方法
                CloseConnectionSpecific(closeDueToError, logLocation);

#if !NETFX_CORE
                try
                {
                    //If we are calling close from the listen thread we are actually in the same thread
                    //We must guarantee the listen thread stops even if that means we need to nuke it
                    //If we did not we may not be able to shutdown properly.
                    //如果我们从监听线程调用Close,我们实际上是在同一个线程
                    //我们必须保证监听线程停止
                    //否则我们可能无法正常关闭

                    if (incomingDataListenThread != null && incomingDataListenThread != Thread.CurrentThread && (incomingDataListenThread.ThreadState == System.Threading.ThreadState.WaitSleepJoin || incomingDataListenThread.ThreadState == System.Threading.ThreadState.Running))
                    {
                        //If we have made it this far we give the thread a further 50ms to finish before nuking.
                        //如果我们这么做,我们给线程50ms来完成相应的事情
                        ))
                        {
                            incomingDataListenThread.Abort();
                            if (NetworkComms.LoggingEnabled && ConnectionInfo != null) NetworkComms.Logger.Warn("Incoming data listen thread with " + ConnectionInfo + " aborted.");
                        }
                    }
                }
                catch (Exception)
                {

                }
#endif
                //Close connection my get called multiple times for a given connection depending on the reason for being closed
                //根据关闭的原因 我们可能会多次调用 Close connection
                bool firstClose = NetworkComms.RemoveConnectionReference(this);

                try
                {
                    //Almost there
                    //Last thing is to call any connection specific shutdown delegates
                    //最后来调用连接指定关闭委托
                    if (firstClose && ConnectionSpecificShutdownDelegate != null)
                    {
                        if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Debug("Triggered connection specific shutdown delegates with " + ConnectionInfo);
                        ConnectionSpecificShutdownDelegate(this);
                    }
                }
                catch (Exception ex)
                {
                    LogTools.LogException(ex, "ConnectionSpecificShutdownDelegateError", "Error while executing connection specific shutdown delegates for " + ConnectionInfo + ". Ensure any shutdown exceptions are caught in your own code.");
                }

                try
                {
                    //Last but not least we call any global connection shutdown delegates
                    //调用全局连接关闭委托
                    if (firstClose && NetworkComms.globalConnectionShutdownDelegates != null)
                    {
                        if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Debug("Triggered global shutdown delegates with " + ConnectionInfo);
                        NetworkComms.globalConnectionShutdownDelegates(this);
                    }
                }
                catch (Exception ex)
                {
                    LogTools.LogException(ex, "GlobalConnectionShutdownDelegateError", "Error while executing global connection shutdown delegates for " + ConnectionInfo + ". Ensure any shutdown exceptions are caught in your own code.");
                }
            }
            catch (Exception ex)
            {
#if !NETFX_CORE
                if (ex is ThreadAbortException)
                { /*Ignore the threadabort exception if we had to nuke a thread*/ }
                else
#endif
                    LogTools.LogException(ex, "NCError_CloseConnection", "Error closing connection with " + ConnectionInfo + ". Close called from " + logLocation.ToString() + (closeDueToError ? " due to error." : "."));

                //We try to rethrow where possible but CloseConnection could very likely be called from within networkComms so we just have to be happy with a log here
                //记录日志
            }
        }

        /// <summary>
        /// Every connection will probably have to perform connection specific shutdown tasks. This is called before the global
        /// connection close tasks.
        /// 连接关闭的具体方法
        /// </summary>
        /// <param name="closeDueToError">Closing a connection due an error possibly requires a few extra steps.</param>
        /// <param name="logLocation">Optional debug parameter for determining the location of the close.</param>
        );

        /// <summary>
        /// Uses the current connection and returns a bool dependant on the remote end responding to a SendReceiveObject call
        /// within the default <see cref="NetworkComms.ConnectionAliveTestTimeoutMS"/>
        /// 连接是否为活动状态
        /// </summary>
        /// <returns>True if the remote end responds within <see cref="NetworkComms.ConnectionAliveTestTimeoutMS"/> otherwise false</returns>
        public bool ConnectionAlive()
        {
            return ConnectionAlive(NetworkComms.ConnectionAliveTestTimeoutMS);
        }

        /// <summary>
        /// Uses the current connection and returns a bool dependant on the remote end responding to a SendReceiveObject call
        /// within the provided aliveRespondTimeoutMS.
        ///  连接是否为活动状态
        /// </summary>
        /// <param name="aliveRespondTimeoutMS">超时时间  The time to wait in milliseconds before returning false</param>
        /// <returns>True if the remote end responds within the provided aliveRespondTimeoutMS</returns>
        public bool ConnectionAlive(int aliveRespondTimeoutMS)
        {
            long responseTime;
            return ConnectionAlive(aliveRespondTimeoutMS, out responseTime);
        }

        /// <summary>
        /// Uses the current connection and returns a bool dependant on the remote end responding to a SendReceiveObject call
        /// within the provided aliveRespondTimeoutMS
        /// 连接是否为活动状态
        /// </summary>
        /// <param name="aliveRespondTimeoutMS">超时时间 The time to wait in milliseconds before returning false</param>
        /// <param name="responseTimeMS">回复时间  The number of milliseconds taken for a successful response to be received</param>
        /// <returns></returns>
        public bool ConnectionAlive(int aliveRespondTimeoutMS, out long responseTimeMS)
        {
            System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
            responseTimeMS = long.MaxValue;

            if (ConnectionInfo.ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled)
            {
                //We wait for TCP connections to be established
                //等待TCP连接创建
                if (ConnectionInfo.ConnectionType == ConnectionType.TCP && ConnectionInfo.ConnectionState != ConnectionState.Established)
                {
                    if ((DateTime.Now - ConnectionInfo.ConnectionCreationTime).Milliseconds > NetworkComms.ConnectionEstablishTimeoutMS)
                    {
                        CloseConnection();
                        return false;
                    }
                    else
                        return true;
                }
                else
                {
                    try
                    {
                        timer.Start();
                        SendReceiveObject<], NetworkComms.InternalFixedSendReceiveOptions, NetworkComms.InternalFixedSendReceiveOptions);
                        timer.Stop();

                        responseTimeMS = timer.ElapsedMilliseconds;

                        if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("ConnectionAliveTest success, response in " + timer.ElapsedMilliseconds.ToString() + "ms.");

                        return true;
                    }
                    catch (Exception)
                    {
                        CloseConnection();
                        return false;
                    }
                }
            }
            else
                return false;
        }

        /// <summary>
        /// Send the provided packet to the remoteEndPoint. Waits for receive confirmation if required.
        /// 发送数据包到远端点上  等待接收确认消息(如果需要)
        /// </summary>
        /// <typeparam name="packetPayloadObjectType">The type of object encapsulated by the provided packet</typeparam>
        /// <param name="packet">The packet to send</param>
        public void SendPacket<packetPayloadObjectType>(IPacket packet)
        {
            long packetSequenceNumber;
            SendPacket<packetPayloadObjectType>(packet, out packetSequenceNumber);
        }

        /// <summary>
        /// Send the provided packet to the remoteEndPoint. Waits for receive confirmation if required.
        /// 发送数据包到远端点上  等待接收确认消息(如果需要)
        /// </summary>
        /// <typeparam name="packetPayloadObjectType">The type of object encapsulated by the provided packet</typeparam>
        /// <param name="packet">数据包  The packet to send</param>
        /// <param name="packetSequenceNumber">顺序号  The sequence number of the packet sent</param>
        public void SendPacket<packetPayloadObjectType>(IPacket packet, out long packetSequenceNumber)
        {
            if (NetworkComms.LoggingEnabled)
            {
                string packetDataMD5 = "";
                if (packet.PacketHeader.ContainsOption(PacketHeaderStringItems.CheckSumHash))
                    packetDataMD5 = packet.PacketHeader.GetOption(PacketHeaderStringItems.CheckSumHash);

                NetworkComms.Logger.Trace("Entering packet send of '" + packet.PacketHeader.PacketType + "' packetType to " + ConnectionInfo + (packetDataMD5 == "" ? "" : ". PacketCheckSum="+packetDataMD5));
            }

            if (packet.PacketHeader.ContainsOption(PacketHeaderStringItems.ReceiveConfirmationRequired) &&
                ConnectionInfo.ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Disabled)
                throw new ArgumentException("Provided sendReceiveOptions specified ReceiveConfirmationRequired which is invalid for" +
            "connections which do not enable the application protocol. Please check provided sendReceiveOptions including global defaults and try again.");

            //Multiple threads may try to send packets at the same time so wait one at a time here
            //同步锁  多防止个线程可能同时发送数据包
            lock (sendLocker)
            {
                //We don't allow sends on a closed connection
                //不允许在关闭的连接上发送数据
                if (ConnectionInfo.ConnectionState == ConnectionState.Shutdown) throw new CommunicationException("Attempting to send packet on connection which has been closed or is currently closing.");

                //Set packet sequence number inside sendLocker
                //设置数据包的顺序号
                //Increment the global counter as well to ensure future connections with the same host can not create duplicates
                //顺序号自增长 确保不会重复
                Interlocked.Increment(ref NetworkComms.totalPacketSendCount);
                packetSequenceNumber = packetSequenceCounter++;
                packet.PacketHeader.SetOption(PacketHeaderLongItems.PacketSequenceNumber, packetSequenceNumber);

                //string confirmationCheckSum = "";
                long expectedPacketSequenceConfirmationNumber = packetSequenceNumber;
                AutoResetEvent confirmationWaitSignal = new AutoResetEvent(false);
                bool remotePeerDisconnectedDuringWait = false;

                #region Delegates
                //Specify a delegate we may use if we require receive confirmation
                //指定一个委托,如果需要接收确认消息
                NetworkComms.PacketHandlerCallBackDelegate<long> confirmationDelegate = (packetHeader, connectionInfo, incomingSequenceIdentifier) =>
                {
                    //A better method for confirming packets is to use the sending sequence number
                    //确认数据包一个好的方法 即使用发送的顺序号
                    if (incomingSequenceIdentifier == expectedPacketSequenceConfirmationNumber)
                        confirmationWaitSignal.Set();
                };

                //We use the following delegate to quickly force a response timeout if the remote end disconnects during a send/wait
                //如果对方掉线 设置立即超时
                NetworkComms.ConnectionEstablishShutdownDelegate ConfirmationShutDownDelegate = (connectionInfo) =>
                {
                    remotePeerDisconnectedDuringWait = true;
                    confirmationWaitSignal.Set();
                };
                #endregion

                try
                {
                    #region Prepare For Confirmation and Possible Validation
                    //Add the confirmation handler if required
                    //如果需要添加确认收到数据包处理器
                    if (packet.PacketHeader.ContainsOption(PacketHeaderStringItems.ReceiveConfirmationRequired))
                    {
                        AppendIncomingPacketHandler(Enum.GetName(typeof(ReservedPacketType), ReservedPacketType.Confirmation), confirmationDelegate, NetworkComms.InternalFixedSendReceiveOptions);
                        AppendShutdownHandler(ConfirmationShutDownDelegate);
                    }

                    //If this packet is not a checkSumFailResend
                    //如果此数据包的类型不是 checkSumFailResend
                    if (NetworkComms.EnablePacketCheckSumValidation && packet.PacketHeader.PacketType != Enum.GetName(typeof(ReservedPacketType), ReservedPacketType.CheckSumFailResend))
                    {
                        //We only want to keep packets when they are under some provided threshold
                        //otherwise this becomes a quick 'memory leak'
                        //获取数据包的哈希值 数据包的大小不能大于设定值(NetworkComms.CheckSumMismatchSentPacketCacheMaxByteLimit)
                        if (packet.PacketData.Length < NetworkComms.CheckSumMismatchSentPacketCacheMaxByteLimit)
                        {
                            lock (sentPacketsLocker)
                            {
                                var hash = packet.PacketHeader.GetOption(PacketHeaderStringItems.CheckSumHash);

                                if (!sentPackets.ContainsKey(hash))
                                    sentPackets.Add(hash, new SentPacket(packet));
                            }
                        }
                    }
                    #endregion

                    SendPacketSpecific(packet);

                    #region SentPackets Cleanup
                    //If sent packets is greater than 40 we delete anything older than a minute
                    //如果发送的数据包大于40 我们删除一分钟之前发送的数据
                    lock (sentPacketsLocker)
                    {
                        )
                        {
                            Dictionary<string, SentPacket> newSentPackets = new Dictionary<string, SentPacket>();
                            DateTime thresholdTime = DateTime.Now.AddMinutes(-NetworkComms.MinimumSentPacketCacheTimeMinutes);
                            foreach (var storedPacket in sentPackets)
                            {
                                if (storedPacket.Value.SentPacketCreationTime >= thresholdTime)
                                    newSentPackets.Add(storedPacket.Key, storedPacket.Value);
                            }

                            sentPackets = newSentPackets;
                            NetworkComms.LastSentPacketCacheCleanup = DateTime.Now;
                        }
                    }
                    #endregion

                    #region Wait For Confirmation If Required
                    //If we required receive confirmation we now wait for that confirmation
                    //如果我们需要对方确认收到消息  在此处等待
                    if (packet.PacketHeader.ContainsOption(PacketHeaderStringItems.ReceiveConfirmationRequired))
                    {
                        if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... waiting for receive confirmation packet.");

#if NET2
                        if (!(confirmationWaitSignal.WaitOne(NetworkComms.PacketConfirmationTimeoutMS, false)))
#else
                        if (!(confirmationWaitSignal.WaitOne(NetworkComms.PacketConfirmationTimeoutMS)))
#endif
                            throw new ConfirmationTimeoutException("Confirmation packet timeout.");

                        if (remotePeerDisconnectedDuringWait)
                            throw new ConfirmationTimeoutException("Remote end closed connection before confirmation packet was returned.");
                        else
                        {
                            if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... confirmation packet received.");
                        }
                    }
                    #endregion

                    //Update the traffic time as late as possible in case there is a problem
                    //更新ConnectionInfo中的数据包的传输时间
                    ConnectionInfo.UpdateLastTrafficTime();
                }
                catch (ConfirmationTimeoutException)
                {
                    //Confirmation timeout there is no need to close the connection as this
                    //does not necessarily mean there is a connection problem
                    //确认消息超时异常
                    throw;
                }
                catch (CommunicationException)
                {
                    //We close the connection due to communication exceptions
                    //通信异常
                    CloseConnection();
                    throw;
                }
                catch (TimeoutException ex)
                {

                    //We close the connection due to communication exceptions
                    //超时异常
                    if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Warn("Timeout exception for connection " + this.ConnectionInfo + (ex.Message != null ? ". " +ex.Message : "."));

                    CloseConnection();
                    throw new ConnectionSendTimeoutException(ex.ToString());
                }
                catch (Exception ex)
                {
                    //We close the connection due to communication exceptions
                    //异常
                    CloseConnection();
                    throw new CommunicationException(ex.ToString());
                }
                finally
                {
                    if (packet.PacketHeader.ContainsOption(PacketHeaderStringItems.ReceiveConfirmationRequired))
                    {
                        //Clean-up our delegates
                        //清理我们的委托
                        RemoveIncomingPacketHandler(Enum.GetName(typeof(ReservedPacketType), ReservedPacketType.Confirmation), confirmationDelegate);
                        RemoveShutdownHandler(ConfirmationShutDownDelegate);
                    }
                }
            }

            if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("Completed packet send of '" + packet.PacketHeader.PacketType + "' packetType to " + ConnectionInfo);
        }

        /// <summary>
        /// Implementation for sending a null packets on this connection type. Used for ensuring a connection
        /// is not terminated by an intermediary switch/router due to inactivity.
        /// 发送空数据包
        /// </summary>
        private void SendNullPacket()
        {
            //We don't send null packets for UDP
            //在 UDP连接上不发送空数据包
            if (ConnectionInfo.ConnectionType == ConnectionType.UDP)
                return;

            //We can't send null packets if the application layer is disabled
            //as we have no way to distinguish them on the receiving side
            //如果应用层协议禁用 不发送空数据包 因为此时我们没有方法在接收端识别出他们
            if (ConnectionInfo.ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Disabled)
            {
                if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("Ignoring null packet send to " + ConnectionInfo + " as the application layer protocol is disabled.");
                return;
            }

            try
            {
                //Only once the connection has been established do we send null packets
                //只有在连接创建完成后,我们发送空数据包
                if (ConnectionInfo.ConnectionState == ConnectionState.Established)
                {
                    //Multiple threads may try to send packets at the same time so we need this lock to prevent a thread cross talk
                    //同步锁 防止多个线程同时发送数据包
                    lock (sendLocker)
                    {
                        if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("Sending null packet to " + ConnectionInfo);

                        //Send a single 0 byte
                        //发送一个单字节数据
                        double maxSendTimePerKB = double.MaxValue;
                        if (!NetworkComms.DisableConnectionSendTimeouts)
                        {
                            if (SendTimesMSPerKBCache.Count > MinNumSendsBeforeConnectionSpecificSendTimeout)
                                maxSendTimePerKB = Math.Max(MinimumMSPerKBSendTimeout, SendTimesMSPerKBCache.CalculateMean() + NumberOfStDeviationsForWriteTimeout * SendTimesMSPerKBCache.CalculateStdDeviation());
                            else
                                maxSendTimePerKB = DefaultMSPerKBSendTimeout;
                        }

                        StreamTools.StreamSendWrapper[] streamsToSend = new StreamTools.StreamSendWrapper[]
                        {
                             }), true))
                        }; 

                        SendStreams(streamsToSend, maxSendTimePerKB, );

                        //Update the traffic time after we have written to netStream
                        //更新传输时间
                        ConnectionInfo.UpdateLastTrafficTime();
                    }
                }

                //If the connection is shutdown we should call close
                //连接关闭 调用CloseConnection方法
                );
            }
            catch (Exception)
            {
                CloseConnection();
            }
        }

        /// <summary>
        /// Send the provided packet
        /// 发送数据包的具体方法
        /// </summary>
        /// <param name="packet"></param>
        private void SendPacketSpecific(IPacket packet)
        {
            byte[] headerBytes;

            //Serialise the header
            //序列化包头
            if (ConnectionInfo.ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled)
                headerBytes = packet.SerialiseHeader(NetworkComms.InternalFixedSendReceiveOptions);
            else
            {
                //If this connection does not use the application layer protocol we need to check a few things
                //如果连接没有使用应用层协议 我们需要做一些检测
                headerBytes = ];

                if (packet.PacketHeader.PacketType != Enum.GetName(typeof(ReservedPacketType), ReservedPacketType.Unmanaged))
                    throw new UnexpectedPacketTypeException("Only 'Unmanaged' packet types can be used if the NetworkComms.Net application layer protocol is disabled.");

                )
                    throw new NotSupportedException("Sending a zero length array if the NetworkComms.Net application layer protocol is disabled is not supported.");
            }

            double maxSendTimePerKB = double.MaxValue;
            if (!NetworkComms.DisableConnectionSendTimeouts)
            {
                if (SendTimesMSPerKBCache.Count > MinNumSendsBeforeConnectionSpecificSendTimeout)
                    maxSendTimePerKB = Math.Max(MinimumMSPerKBSendTimeout, SendTimesMSPerKBCache.CalculateMean() + NumberOfStDeviationsForWriteTimeout * SendTimesMSPerKBCache.CalculateStdDeviation());
                else
                    maxSendTimePerKB = DefaultMSPerKBSendTimeout;
            }

            if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Debug("Sending a packet of type '" + packet.PacketHeader.PacketType + "' to " +
                ConnectionInfo + " containing " + headerBytes.Length.ToString() + " header bytes and " + packet.PacketData.Length.ToString() + " payload bytes. Allowing " +
                maxSendTimePerKB.ToString("0.0##") + " ms/KB for send.");

            DateTime startTime = DateTime.Now;

            StreamTools.StreamSendWrapper[] streamsToSend = new StreamTools.StreamSendWrapper[]
            { new StreamTools.StreamSendWrapper(new StreamTools.ThreadSafeStream(new MemoryStream(headerBytes), true)),
                packet.PacketData};

            ;
            foreach (StreamTools.StreamSendWrapper stream in streamsToSend)
                totalBytesToSend += stream.Length;

            //Send the streams 发送数据流
            double[] timings = SendStreams(streamsToSend, maxSendTimePerKB, totalBytesToSend);

            //Record the timings 记录时间
            ;
            ; i < timings.Length; i++)
            {
                timingsSum += timings[i];
                SendTimesMSPerKBCache.AddValue(timings[i], streamsToSend[i].Length);
            }

            SendTimesMSPerKBCache.TrimList(MaxNumSendTimes);

            if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... " + (totalBytesToSend / 1024.0).ToString("0.000") + "KB sent at average of " + ((totalBytesToSend / 1024.0) / (DateTime.Now - startTime).TotalSeconds).ToString("0.000") + "KB/s. Current:" + (timingsSum / timings.Length).ToString("0.00") + " ms/KB, Connection Avg:" + SendTimesMSPerKBCache.CalculateMean().ToString("0.00") + " ms/KB.");
        }

        /// <summary>
        /// Connection specific implementation for sending data on this connection type.
        /// Each StreamSendWrapper[] represents a single expected packet.
        /// 发送数据流
        /// </summary>
        /// <param name="streamsToSend">数据流   The streams which need to be sent</param>
        /// <param name="maxSendTimePerKB">每KB数据最长的发送时间  The maximum time to allow per KB before a write timeout exception.</param>
        /// <param name="totalBytesToSend">总共需要发送的字节数量  A precalculated sum of streams.Length</param>
        /// <returns>Should return double[] which represents the milliseconds per byte written for each StreamSendWrapper</returns>
        protected abstract double[] SendStreams(StreamTools.StreamSendWrapper[] streamsToSend, double maxSendTimePerKB, long totalBytesToSend);

        /// <summary>
        /// Dispose of the connection. Recommended usage is to call CloseConnection instead.
        /// 释放连接  推荐使用CloseConnection替代
        /// </summary>
        public void Dispose()
        {
            CloseConnection();

            try
            {
                ((IDisposable)connectionSetupWait).Dispose();
                ((IDisposable)connectionEstablishWait).Dispose();
            }
            catch (Exception) { }
        }
    }

介绍开源的.net通信框架NetworkComms框架 源码分析(十七 ) ConnectionSendClose的更多相关文章

  1. DotNetty网络通信框架学习之源码分析

    DotNetty网络通信框架学习之源码分析 有关DotNetty框架,网上的详细资料不是很多,有不多的几个博友做了简单的介绍,也没有做深入的探究,我也根据源码中提供的demo做一下记录,方便后期查阅. ...

  2. 深入理解分布式调度框架TBSchedule及源码分析

    简介 由于最近工作比较忙,前前后后花了两个月的时间把TBSchedule的源码翻了个底朝天.关于TBSchedule的使用,网上也有很多参考资料,这里不做过多的阐述.本文着重介绍TBSchedule的 ...

  3. 设计模式(十五)——命令模式(Spring框架的JdbcTemplate源码分析)

    1 智能生活项目需求 看一个具体的需求 1) 我们买了一套智能家电,有照明灯.风扇.冰箱.洗衣机,我们只要在手机上安装 app 就可以控制对这些家电工作. 2) 这些智能家电来自不同的厂家,我们不想针 ...

  4. 设计模式(二十一)——解释器模式(Spring 框架中SpelExpressionParser源码分析)

    1 四则运算问题 通过解释器模式来实现四则运算,如计算 a+b-c 的值,具体要求 1) 先输入表达式的形式,比如 a+b+c-d+e,  要求表达式的字母不能重复 2) 在分别输入 a ,b, c, ...

  5. $Django cbv源码分析 djangorestframework框架之APIView源码分析

    1 CBV的源码分析 #视图 class login (View): pass #路由 url(r'^books/$', views.login.as_view()) #阅读源码: #左侧工程栏--- ...

  6. ④NuPlayer播放框架之Renderer源码分析

    [时间:2016-11] [状态:Open] [关键词:android,nuplayer,开源播放器,播放框架,渲染器,render] 0 导读 之前我们分析了NuPlayer的实现代码,本文将重点聚 ...

  7. ⑤NuPlayer播放框架之GenericSource源码分析

    [时间:2017-01] [状态:Open] [关键词:android,nuplayer,开源播放器,播放框架,GenericSource] 0 导读 GenericSource是NuPlayer:: ...

  8. ③NuPlayer播放框架之类NuPlayer源码分析

    [时间:2016-10] [状态:Open] [关键词:android,nuplayer,开源播放器,播放框架] 0 引言 差不多一个月了,继续分析AOSP的播放框架的源码.这次我们需要深入分析的是N ...

  9. Laravel开发:Laravel框架门面Facade源码分析

    前言 这篇文章我们开始讲 laravel 框架中的门面 Facade,什么是门面呢?官方文档: Facades(读音:/fəˈsäd/ )为应用程序的服务容器中可用的类提供了一个「静态」接口.Lara ...

  10. Android 应用框架层 SQLite 源码分析

    概述   Android 在应用框架层为开发者提供了 SQLite 相关操作接口,其归属于android.database.sqlite包底下,主要包含SQLiteProgram, SQLiteDat ...

随机推荐

  1. java.sql.SQLException: No suitable driver 问题解决

    最近在学习java,用到c3p0数据库连接池,遇到一个很奇怪的现象,用main方法测试是可以正常连接数据库的,但是使用jsp调用代码,就会报如下图的错误! 最下面的java.sql.SQLExcept ...

  2. 推荐10个很棒的AngularJS学习指南

    AngularJS 是非常棒的JS框架,能够创建功能强大,动态功能的Web app.AngularJS自2009发布以来,已经广泛应用于Web 开发中.但是对想要学习Angular JS 的人而言,只 ...

  3. linux网络编程系列-网络连接的建立

    一个比较实用的连接函数,支持host为域名. #include <netdb.h> #include <sys/socket.h> #include <sys/types ...

  4. 关于redis启动流程介绍

    转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/94.html?1455870894 1. 准备运行环境 * 设置oom h ...

  5. GridView和DATAGRID前后台查询用法的比较

    Grideview前台: <DIV class="mainDiv" id="GridWidth"> <ASP:GridView id=&quo ...

  6. 将图片的二进制字节字符串在HTML页面以图片形式输出

    具体实现代码如下: 1.新建一个一般处理程序: Image.ashx using System; using System.Collections.Generic; using System.Linq ...

  7. AngularJS $http配置为form data 提交

    AngularJS $http配置为form data 提交 $scope.formData = {}; $http({ method: 'POST', url: '/user/', // pass ...

  8. PHP两种redirect

    PHP两种redirect redirect header('Location: /admin_data.php'); exit(); redirect `echo "<script& ...

  9. Java 集合 — HashMap

    HashMap 无序(每次resize的时候都会变) 非线程安全 key和value都看可以为null 使用数组和链表实现 查找元素的时候速度快 几个重要属性: loadFactor:用来计算thre ...

  10. MySQL(四) 数据表的插入、更新、删除数据

    序言 数据表的插入.更新.删除非常简单,但是简单的也要学习,细节决定成败. ---WH 一.插入数据 格式:INSERT INTO 表名(字段名...)VALUES(值...); 创建环境 使用per ...