首页 技术 正文
技术 2022年11月7日
0 收藏 401 点赞 1,092 浏览 33417 个字

原文网址: 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) { }        }    }
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,487
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,903
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,736
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,487
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,127
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,289