原文网址: 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. 【OpenGL(SharpGL)】支持任意相机可平移缩放的轨迹球实现

    [OpenGL(SharpGL)]支持任意相机可平移缩放的轨迹球 (本文PDF版在这里.) 在3D程序中,轨迹球(ArcBall)可以让你只用鼠标来控制模型(旋转),便于观察.在这里(http://w ...

  2. boost常用记录

    1.BOOST_FOREACH 经常会遍历容器,写for/while循环到手痛,使用BOOST_FOREACH可以减少我们的工作.支持容器vector/list/set/deque/stack/que ...

  3. Atitit 图像清晰度 模糊度 检测 识别 评价算法 源码实现attilax总结

    Atitit 图像清晰度 模糊度 检测 识别 评价算法 源码实现attilax总结 1.1. 原理,主要使用像素模糊后的差别会变小1 1.2. 具体流程1 1.3. 提升性能 可以使用采样法即可..1 ...

  4. Atian inputmethod 输入法解决方案 方言与多语言多文字支持 英语汉字汉语阿拉伯文的支持 (au

    Atian inputmethod 输入法解决方案 方言与多语言多文字支持 英语汉字汉语阿拉伯文的支持 (au 1.1. Overview概论 支持母语优先的战略性产品,主要是针对不想以及不愿使用普通 ...

  5. Atitit dsl对于数组的处理以及main函数的参数赋值

    Atitit dsl对于数组的处理以及main函数的参数赋值 1.1. 词法解析..添加了[] 方括号的解析支持1 1.2. Ast建立.添加了数组参数的支持..使用了递归下降法..getparam ...

  6. OutputCache属性详解(四)— SqlDependency

    目录 OutputCache概念学习 OutputCache属性详解(一) OutputCache属性详解(二) OutputCache属性详解(三) OutputCache属性详解(四)— SqlD ...

  7. 获取当前请求的URL的地址、参数、参数值、各种属性

    //URL: http://localhost:1897/User/Press/UserContent.aspx/9878?id=1#toc Request.ApplicationPath; //结果 ...

  8. SQL Server排序函数row_number和rank的区别

    SQL Server排序函数row_number和rank的区别 直接看测试结果 declare @table table(name varchar(100),amount int, memo var ...

  9. Java学习第一天

    Java学习第一天 对于网络管理员或者黑客必须知道的八个cmd命令 详情请参考:http://www.2cto.com/os/201608/533964.html          nbtstat  ...

  10. Oracle 11g系列:视图

    视图是数据库中特有的对象,视图用于存储查询,但不会存储数据(物化视图除外).这是视图和数据表的重要区别.Oracle中有4种视图:关系视图.内嵌视图.对象视图和物化视图. 1.关系视图 1>.创 ...