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

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

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

/// <summary>
    /// A connection object which utilises <see href="http://en.wikipedia.org/wiki/Transmission_Control_Protocol">TCP</see> to communicate between peers.
    /// Tcp连接对象   通过TCP协议在端点之间通信
    /// </summary>
    public sealed partial class TCPConnection : IPConnection
    {
#if WINDOWS_PHONE || NETFX_CORE
        /// <summary>
        /// The windows phone socket corresponding to this connection.
        /// </summary>
        StreamSocket socket;
#else
        /// <summary>
        /// The TcpClient corresponding to this connection.
        /// 与此连接相关的TcpClient对象
        /// </summary>
        TcpClient tcpClient;

        /// <summary>
        /// The networkstream associated with the tcpClient.
        /// 与tcpClient相对应额networkstream对象
        /// </summary>
        Stream connectionStream;

        /// <summary>
        /// The SSL options associated with this connection.
        /// SSL(安全套接层) 相关的参数设置
        /// </summary>
        public SSLOptions SSLOptions { get; private set; }
#endif

        /// <summary>
        /// The current incoming data buffer
        ///  进入的数据的缓冲区
        /// </summary>
        byte[] dataBuffer;

        /// <summary>
        /// TCP connection constructor
        /// TCP连接构造器
        /// </summary>
#if WINDOWS_PHONE || NETFX_CORE
        private TCPConnection(ConnectionInfo connectionInfo, SendReceiveOptions defaultSendReceiveOptions, StreamSocket socket)
#else
        private TCPConnection(ConnectionInfo connectionInfo, SendReceiveOptions defaultSendReceiveOptions, TcpClient tcpClient, SSLOptions sslOptions)
#endif
            : base(connectionInfo, defaultSendReceiveOptions)
        {
            if (connectionInfo.ConnectionType != ConnectionType.TCP)
                throw new ArgumentException("Provided connectionType must be TCP.", "connectionInfo");

            dataBuffer = new byte[NetworkComms.InitialReceiveBufferSizeBytes];

            //We don't guarantee that the tcpClient has been created yet
            //在构造器中  tcpClient对象可能还没有被创建
#if WINDOWS_PHONE || NETFX_CORE
            if (socket != null) this.socket = socket;
#else
            if (tcpClient != null) this.tcpClient = tcpClient;
            this.SSLOptions = sslOptions;
#endif
        }

        /// <inheritdoc />
        /// 创建Tcp连接
        protected override void EstablishConnectionSpecific()
        {
#if WINDOWS_PHONE || NETFX_CORE
            if (socket == null) ConnectSocket();

            //For the local endpoint
            //本地端点
            var localEndPoint = new IPEndPoint(IPAddress.Parse(socket.Information.LocalAddress.CanonicalName.ToString()), int.Parse(socket.Information.LocalPort));

            //We should now be able to set the connectionInfo localEndPoint
            //此处 可以设置connectionInfo对象的本地端点
            NetworkComms.UpdateConnectionReferenceByEndPoint(this, ConnectionInfo.RemoteIPEndPoint, localEndPoint);
            ConnectionInfo.UpdateLocalEndPointInfo(localEndPoint);

            //Set the outgoing buffer size
            //设置发送缓冲区大小
            socket.Control.OutboundBufferSizeInBytes = (uint)NetworkComms.SendBufferSizeBytes;
#else
            if (tcpClient == null) ConnectSocket();

            //We should now be able to set the connectionInfo localEndPoint
            //我们现在应该能够设置 connectionInfo对象的本地端点
            NetworkComms.UpdateConnectionReferenceByEndPoint(this, ConnectionInfo.RemoteIPEndPoint, (IPEndPoint)tcpClient.Client.LocalEndPoint);
            ConnectionInfo.UpdateLocalEndPointInfo((IPEndPoint)tcpClient.Client.LocalEndPoint);

            if (SSLOptions.SSLEnabled)
                ConfigureSSLStream();
            else
                //We are going to be using the networkStream quite a bit so we pull out a reference once here
                //networkStream类型的网络流 后面会有不少地方需要使用 此处做一个引用
                connectionStream = tcpClient.GetStream();

            //When we tell the socket/client to close we want it to do so immediately  当我们告诉socket/client关闭时 我们希望其立即关闭
            //this.tcpClient.LingerState = new LingerOption(false, 0);

            //We need to set the keep alive option otherwise the connection will just die at some random time should we not be using it
            //我们需要设定Keep alive选项 以防止连接断开  (后来没有使用)
            //NOTE: This did not seem to work reliably so was replaced with the keepAlive packet feature
            //注意:设定KeepAlive选项来维护Tcp连接并不可靠   所以后来我们用发送心跳包进行代替
            //this.tcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);

            tcpClient.ReceiveBufferSize = NetworkComms.MaxReceiveBufferSizeBytes;
            tcpClient.SendBufferSize = NetworkComms.SendBufferSizeBytes;

            //This disables the 'nagle algorithm' 禁用 nagle算法
            //http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.nodelay.aspx
            //Basically we may want to send lots of small packets (<200 bytes) and sometimes those are time critical (e.g. when establishing a connection)
            //If we leave this enabled small packets may never be sent until a suitable send buffer length threshold is passed. i.e. BAD
            //下面的2个选项设定为true,当Tcp连接上有数据时,立即发送,我符合我们的预期。而不是等待Tcp缓冲池中有足够多的数据才一起发送
            tcpClient.NoDelay = true;
            tcpClient.Client.NoDelay = true;
#endif

            //Start listening for incoming data
            //开始监听进来的数据
            StartIncomingDataListen();

            //If the application layer protocol is enabled we handshake the connection
            //如果应用层协议启用 连接进行握手操作
            //应用层协议,系统默认为启用
            if (ConnectionInfo.ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled)
                ConnectionHandshake();
            else
            {
                //If there is no handshake we can now consider the connection established
                //如果此处无握手操作 我们可以考虑创建连接
                TriggerConnectionEstablishDelegates();

                //Trigger any connection setup waits
                //触发任何连接建设等待
                connectionSetupWait.Set();
            }

#if !WINDOWS_PHONE && !NETFX_CORE
            //Once the connection has been established we may want to re-enable the 'nagle algorithm' used for reducing network congestion (apparently).
            //By default we leave the nagle algorithm disabled because we want the quick through put when sending small packets
            //一旦连接建立了,某些情况下我们可能要重新启用“Nagle算法”用于减少网络拥塞。
            //默认情况下我们不启用 nagle 算法,启用nagle算法将导致小的数据不能被及时的发送
            if (EnableNagleAlgorithmForNewConnections)
            {
                tcpClient.NoDelay = false;
                tcpClient.Client.NoDelay = false;
            }
#endif
        }

        /// <summary>
        /// If we were not provided with a tcpClient on creation we need to create one
        /// 如果没有tcpClient对象则创建一个
        /// </summary>
        private void ConnectSocket()
        {
            try
            {
                if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("Connecting TCP client with " + ConnectionInfo);

                bool connectSuccess = true;
#if WINDOWS_PHONE || NETFX_CORE
                //We now connect to our target
                //我们现在开始连接到我们的目标
                socket = new StreamSocket();
                socket.Control.NoDelay = !EnableNagleAlgorithmForNewConnections;

                CancellationTokenSource cancelAfterTimeoutToken = new CancellationTokenSource(NetworkComms.ConnectionEstablishTimeoutMS);

                try
                {
                    if (ConnectionInfo.LocalEndPoint != null && ConnectionInfo.LocalIPEndPoint.Address != IPAddress.IPv6Any && ConnectionInfo.LocalIPEndPoint.Address != IPAddress.Any)
                    {
                        var endpointPairForConnection = new Windows.Networking.EndpointPair(new Windows.Networking.HostName(ConnectionInfo.LocalIPEndPoint.Address.ToString()), ConnectionInfo.LocalIPEndPoint.Port.ToString(),
                                                        new Windows.Networking.HostName(ConnectionInfo.RemoteIPEndPoint.Address.ToString()), ConnectionInfo.RemoteIPEndPoint.Port.ToString());                        

                        var task = socket.ConnectAsync(endpointPairForConnection).AsTask(cancelAfterTimeoutToken.Token);
                        task.Wait();
                    }
                    else
                    {
                        var task = socket.ConnectAsync(new Windows.Networking.HostName(ConnectionInfo.RemoteIPEndPoint.Address.ToString()), ConnectionInfo.RemoteIPEndPoint.Port.ToString()).AsTask(cancelAfterTimeoutToken.Token);
                        task.Wait();
                    }
                }
                catch (Exception)
                {
                    socket.Dispose();
                    connectSuccess = false;
                }
#else
                //We now connect to our target
                //我们现在开始连接到我们的目标
                tcpClient = new TcpClient(ConnectionInfo.RemoteEndPoint.AddressFamily);

                //Start the connection using the async version
                //以异步方式开始连接
                //This allows us to choose our own connection establish timeout
                //允许设定连接创建超时时间
                IAsyncResult ar = tcpClient.BeginConnect(ConnectionInfo.RemoteIPEndPoint.Address, ConnectionInfo.RemoteIPEndPoint.Port, null, null);
                WaitHandle connectionWait = ar.AsyncWaitHandle;
                try
                {
                    if (!connectionWait.WaitOne(NetworkComms.ConnectionEstablishTimeoutMS, false))
                        connectSuccess = false;
                    else
                        tcpClient.EndConnect(ar);
                }
                finally
                {
                    connectionWait.Close();
                }
#endif

                if (!connectSuccess) throw new ConnectionSetupException("Timeout waiting for remoteEndPoint to accept TCP connection.");
            }
            catch (Exception ex)
            {
                CloseConnection();
                throw new ConnectionSetupException("Error during TCP connection establish with destination (" + ConnectionInfo + "). Destination may not be listening or connect timed out. " + ex.ToString());
            }
        }

        /// <inheritdoc />
        /// 开始监听进入的数据局
        protected override void StartIncomingDataListen()
        {
            if (!NetworkComms.ConnectionExists(ConnectionInfo.RemoteIPEndPoint, ConnectionInfo.LocalIPEndPoint, ConnectionType.TCP, ConnectionInfo.ApplicationLayerProtocol))
            {
                CloseConnection();
                throw new ConnectionSetupException("A connection reference by endPoint should exist before starting an incoming data listener.");
            }

#if WINDOWS_PHONE
            var stream = socket.InputStream.AsStreamForRead();
            stream.BeginRead(dataBuffer, , dataBuffer.Length, new AsyncCallback(IncomingTCPPacketHandler), stream);
#elif NETFX_CORE
            Task readTask = new Task(async () =>
            {
                var buffer = Windows.Security.Cryptography.CryptographicBuffer.CreateFromByteArray(dataBuffer);
                var readBuffer = await socket.InputStream.ReadAsync(buffer, buffer.Capacity, InputStreamOptions.Partial);
                await IncomingTCPPacketHandler(readBuffer);
            });

            readTask.Start();
#else
            lock (SyncRoot)
            {
                //以同步方式
                if (NetworkComms.ConnectionListenModeUseSync)
                {
                    if (incomingDataListenThread == null)
                    {
                        //创建一个线程
                        incomingDataListenThread = new Thread(IncomingTCPDataSyncWorker);
                        //Incoming data always gets handled in a time critical fashion
                        //设定数据处理的优先级
                        incomingDataListenThread.Priority = NetworkComms.timeCriticalThreadPriority;
                        incomingDataListenThread.Name = "UDP_IncomingDataListener";
                        incomingDataListenThread.IsBackground = true;
                        incomingDataListenThread.Start();
                    }
                }
                //以异步方式处理
                else
                {
                    if (asyncListenStarted) throw new ConnectionSetupException("Async listen already started. Why has this been called twice?.");

                    asyncListenerInRead = true;
                    //开始读取连接上的数据
                    connectionStream.BeginRead(dataBuffer, , dataBuffer.Length, new AsyncCallback(IncomingTCPPacketHandler), connectionStream);

                    asyncListenStarted = true;
                }
            }
#endif

            if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("Listening for incoming data from " + ConnectionInfo);
        }

        /// <summary>
        /// Asynchronous incoming connection data delegate
        /// 以异步的方式处理连接上的数据
        /// </summary>
        /// <param name="ar">The call back state object</param> 回调状态对象
#if NETFX_CORE
        private async Task IncomingTCPPacketHandler(IBuffer buffer)
#else
        private void IncomingTCPPacketHandler(IAsyncResult ar)
#endif
        {
            //Initialised with false so that logic still works in WP8
            //初始化状态为false  所以可以在wp8系统下运行
            bool dataAvailable = false;

#if !WINDOWS_PHONE && !NETFX_CORE
            //Incoming data always gets handled in a timeCritical fashion at this point
            //Windows phone and RT platforms do not support thread priorities
            //设定数据处理的优先级
            //wp 和rt平台不支持线程优先级的设定
            Thread.CurrentThread.Priority = NetworkComms.timeCriticalThreadPriority;
#endif

            try
            {
#if WINDOWS_PHONE
                Stream stream = ar.AsyncState as Stream;
                totalBytesRead = stream.EndRead(ar) + totalBytesRead;
#elif NETFX_CORE
                buffer.CopyTo(, dataBuffer, totalBytesRead, (int)buffer.Length);
                totalBytesRead = (int)buffer.Length + totalBytesRead;
#else
                Stream stream;
                if (SSLOptions.SSLEnabled)
                    stream = (SslStream)ar.AsyncState;
                else
                    stream = (NetworkStream)ar.AsyncState;

                if (!stream.CanRead)
                    throw new ObjectDisposedException("Unable to read from stream.");

                if (!asyncListenerInRead) throw new InvalidDataException("The asyncListenerInRead flag should be true. 1");
                totalBytesRead = stream.EndRead(ar) + totalBytesRead;
                asyncListenerInRead = false;

                if (SSLOptions.SSLEnabled)
                    //SSLstream does not have a DataAvailable property. We will just assume false.
                    //SSLstream (安全套接层)数据流    不支持DataAvailable属性
                    dataAvailable = false;
                else
                    dataAvailable = ((NetworkStream)stream).DataAvailable;
#endif
                )
                {
                    ConnectionInfo.UpdateLastTrafficTime();

                    //If we have read a single byte which is 0 and we are not expecting other data
                    //如果只读取到一个字节,内容为0 (猜测这样的单字节一般用于心跳检测)
                    if (ConnectionInfo.ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled &&
                        totalBytesRead ==  && dataBuffer[] ==  && packetBuilder.TotalBytesExpected - packetBuilder.TotalBytesCached == )
                    {
                        if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... null packet removed in IncomingPacketHandler() from " + ConnectionInfo + ". 1");
                    }
                    else
                    {
                        if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... " + totalBytesRead.ToString() + " bytes added to packetBuilder for " + ConnectionInfo + ". Cached " + packetBuilder.TotalBytesCached.ToString() + " bytes, expecting " + packetBuilder.TotalBytesExpected.ToString() + " bytes.");

                        //If there is more data to get then add it to the packets lists;
                        //packetBuilder  数据包创建器
                        //把读取到的字节添加到"数据包创建器"中
                        //totalBytesRead  此次读取到的字节数量(int类型)   dataBuffer  (byte[] 字节数组)
                        packetBuilder.AddPartialPacket(totalBytesRead, dataBuffer);

#if !WINDOWS_PHONE && !NETFX_CORE
                        //If we have more data we might as well continue reading synchronously
                        //In order to deal with data as soon as we think we have sufficient we will leave this loop
                        //如果我们有更多的数据 继续同步读取
                        //如果接收到的数据足够多,将离开此循环
                        //根据networkcomms的机制,第一个字节为数据包包头大小,系统会根据数据包包头大小解析出数据包包头,从数据包包头中读取数据包大小
                        //这个数据包大小就是packetBuilder中totalBytesExpected,即期望的大小
                        while (dataAvailable && packetBuilder.TotalBytesCached < packetBuilder.TotalBytesExpected)
                        {
                            ;

                            //We need a buffer for our incoming data
                            //First we try to reuse a previous buffer
                            //我们需要为进入的数据准备缓冲区
                            //首先我们尝试使用以前的缓冲区
                             && packetBuilder.NumUnusedBytesMostRecentPartialPacket() > )
                                dataBuffer = packetBuilder.RemoveMostRecentPartialPacket(ref bufferOffset);
                            else
                            //If we have nothing to reuse we allocate a new buffer. As we are in this loop this can only be a suplementary buffer for THIS packet.
                            //Therefore we choose a buffer size between the initial amount and the maximum amount based on the expected size
                            //如果没有可重复使用的缓冲区,我们将新分配一个新的缓冲区
                            //缓冲区的大小为  数据包创建器.期待的大小 减去  数据包创建器.已收到的大小  (即 数据包长度 减去  已经接收的长度)
                            {
                                long additionalBytesNeeded = packetBuilder.TotalBytesExpected - packetBuilder.TotalBytesCached;
                                dataBuffer = new byte[Math.Max(Math.Min(additionalBytesNeeded, NetworkComms.MaxReceiveBufferSizeBytes), NetworkComms.InitialReceiveBufferSizeBytes)];
                            }

                            totalBytesRead = stream.Read(dataBuffer, bufferOffset, dataBuffer.Length - bufferOffset) + bufferOffset;

                            )
                            {
                                ConnectionInfo.UpdateLastTrafficTime();

                                //If we have read a single byte which is 0 and we are not expecting other data
                                //处理单字节数据  一般为心跳消息
                                 && dataBuffer[] ==  && packetBuilder.TotalBytesExpected - packetBuilder.TotalBytesCached == )
                                {
                                    if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... null packet ignored in IncomingPacketHandler() from " + ConnectionInfo + ". 2");
                                    //LastTrafficTime = DateTime.Now;
                                }
                                else
                                {
                                    if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... " + totalBytesRead.ToString() + " bytes added to packetBuilder for " + ConnectionInfo + ". Cached " + packetBuilder.TotalBytesCached.ToString() + " bytes, expecting " + packetBuilder.TotalBytesExpected.ToString() + " bytes.");
                                    packetBuilder.AddPartialPacket(totalBytesRead, dataBuffer);

                                    if (SSLOptions.SSLEnabled)

                                        //SSLstream does not have a DataAvailable property. We will just assume false.
                                        //SSLstream 没有DataAvailable属性
                                        dataAvailable = false;
                                    else
                                        dataAvailable = ((NetworkStream)stream).DataAvailable;
                                }
                            }
                            else
                                break;
                        }
#endif
                    }
                }

                 && packetBuilder.TotalBytesCached >= packetBuilder.TotalBytesExpected)
                {
                    //Once we think we might have enough data we call the incoming packet handle hand off
                    //Should we have a complete packet this method will start the appropriate task
                    //This method will now clear byes from the incoming packets if we have received something complete.
                    //一旦我们的数据包创建器(packetBuilder)中接收到足够一个数据包的数据,我们将会对数据进行处理
                    //IncomingPacketHandleHandOff方法处理完packetBuilder中相应的数据后,会把已经处理完的数据删除掉
                    IncomingPacketHandleHandOff(packetBuilder);
                }

                 && (!dataAvailable || ConnectionInfo.ConnectionState == ConnectionState.Shutdown))
                    CloseConnection();
                else
                {
                    //We need a buffer for our incoming data
                    //First we try to reuse a previous buffer

                    //我们需要一个缓冲区来接收数据
                    //我们先尝试使用以前的缓冲区
                     && packetBuilder.NumUnusedBytesMostRecentPartialPacket() > )
                        dataBuffer = packetBuilder.RemoveMostRecentPartialPacket(ref totalBytesRead);
                    else
                    {
                        //If we have nothing to reuse we allocate a new buffer
                        //If packetBuilder.TotalBytesExpected is 0 we know we're going to start waiting for a fresh packet. Therefore use the initial buffer size
                        //如果没有可重复使用的缓冲区,我们将新分配一个新的缓冲区
                        //如果 数据包创建器 期待的数据大小为0,我们将开始接收一个新的数据包的数据   此时 把缓冲区设置为初始大小
                        )
                            dataBuffer = new byte[NetworkComms.InitialReceiveBufferSizeBytes];
                        else
                        //Otherwise this can only be a supplementary buffer for THIS packet. Therefore we choose a buffer size between the initial amount and the maximum amount based on the expected size
                        //如果没有可重复使用的缓冲区,我们将新分配一个新的缓冲区
                        //缓冲区的大小为  数据包创建器.期待的大小 减去  数据包创建器.已收到的大小  (即 数据包长度 减去  已经接收的长度)
                        {
                            long additionalBytesNeeded = packetBuilder.TotalBytesExpected - packetBuilder.TotalBytesCached;
                            dataBuffer = new byte[Math.Max(Math.Min(additionalBytesNeeded, NetworkComms.MaxReceiveBufferSizeBytes), NetworkComms.InitialReceiveBufferSizeBytes)];
                        }

                        totalBytesRead = ;
                    }

#if NETFX_CORE
                    IBuffer newBuffer = Windows.Security.Cryptography.CryptographicBuffer.CreateFromByteArray(dataBuffer);
                    var task = IncomingTCPPacketHandler(await socket.InputStream.ReadAsync(newBuffer, newBuffer.Capacity - (uint)totalBytesRead, InputStreamOptions.Partial));
#elif WINDOWS_PHONE
                    stream.BeginRead(dataBuffer, totalBytesRead, dataBuffer.Length - totalBytesRead, IncomingTCPPacketHandler, stream);
#else
                    if (asyncListenerInRead) throw new InvalidDataException("The asyncListenerInRead flag should be false. 2");
                    asyncListenerInRead = true;
                    stream.BeginRead(dataBuffer, totalBytesRead, dataBuffer.Length - totalBytesRead, IncomingTCPPacketHandler, stream);
#endif
                }

            }
            catch (IOException)
            {
                CloseConnection();
            }
            catch (ObjectDisposedException)
            {
                CloseConnection();
            }
            catch (SocketException)
            {
                CloseConnection();
            }
            catch (InvalidOperationException)
            {
                CloseConnection();
            }
            catch (Exception ex)
            {
                LogTools.LogException(ex, "Error_TCPConnectionIncomingPacketHandler");
                CloseConnection();
            }

#if !WINDOWS_PHONE && !NETFX_CORE
            Thread.CurrentThread.Priority = ThreadPriority.Normal;
#endif
        }

#if !WINDOWS_PHONE && !NETFX_CORE
        /// <summary>
        /// Synchronous incoming connection data worker
        /// 同步处理连接上进入的数据的处理器
        /// </summary>
        private void IncomingTCPDataSyncWorker()
        {
            bool dataAvailable = false;

            try
            {
                while (true)
                {
                    if (ConnectionInfo.ConnectionState == ConnectionState.Shutdown)
                        break;

                    ;

                    //We need a buffer for our incoming data
                    //First we try to reuse a previous buffer
                    //我们需要为进入的数据准备缓冲区
                    //首先我们尝试使用以前的缓冲区
                     && packetBuilder.NumUnusedBytesMostRecentPartialPacket() > )
                        dataBuffer = packetBuilder.RemoveMostRecentPartialPacket(ref bufferOffset);
                    else
                    {
                        //If we have nothing to reuse we allocate a new buffer
                        //If packetBuilder.TotalBytesExpected is 0 we know we're going to start waiting for a fresh packet. Therefore use the initial buffer size
                        //如果没有可重复使用的缓冲区,我们将新分配一个新的缓冲区
                        //如果 数据包创建器 期待的数据大小为0,我们将开始接收一个新的数据包的数据   此时 把缓冲区设置为初始大小
                        )
                            dataBuffer = new byte[NetworkComms.InitialReceiveBufferSizeBytes];
                        else
                        //Otherwise this can only be a supplementary buffer for THIS packet. Therefore we choose a buffer size between the initial amount and the maximum amount based on the expected size
                        //如果没有可重复使用的缓冲区,我们将新分配一个新的缓冲区
                        //缓冲区的大小为  数据包创建器.期待的大小 减去  数据包创建器.已收到的大小  (即 数据包长度 减去  已经接收的长度)
                        {
                            long additionalBytesNeeded = packetBuilder.TotalBytesExpected - packetBuilder.TotalBytesCached;
                            dataBuffer = new byte[Math.Max(Math.Min(additionalBytesNeeded, NetworkComms.MaxReceiveBufferSizeBytes), NetworkComms.InitialReceiveBufferSizeBytes)];
                        }
                    }

                    //We block here until there is data to read
                    //When we read data we read until method returns or we fill the buffer length
                    //程序将会阻塞  直到读取到数据
                    //我们读取数据 直到方法返回或者读取到缓冲区大小的数据
                    totalBytesRead = connectionStream.Read(dataBuffer, bufferOffset, dataBuffer.Length - bufferOffset) + bufferOffset;

                    //Check to see if there is more data ready to be read
                    //检查是否还有数据需要读取
                    if (SSLOptions.SSLEnabled)
                        //SSLstream does not have a DataAvailable property. We will just assume false.
                        //SSLStream没有DataAvailable属性
                        dataAvailable = false;
                    else
                        dataAvailable = ((NetworkStream)connectionStream).DataAvailable;

                    //If we read any data it gets handed off to the packetBuilder
                    //如果我们读取到数据,交给packetBuilder处理
                    )
                    {
                        ConnectionInfo.UpdateLastTrafficTime();

                        //If we have read a single byte which is 0 and we are not expecting other data
                        //处理单字节 内容为0 的数据  (一般为心跳检测)
                         && dataBuffer[] ==  && packetBuilder.TotalBytesExpected - packetBuilder.TotalBytesCached == )
                        {
                            if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... null packet removed in IncomingDataSyncWorker() from "+ConnectionInfo+".");
                        }
                        else
                        {
                            if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... " + totalBytesRead.ToString() + " bytes added to packetBuilder for " + ConnectionInfo + ". Cached " + packetBuilder.TotalBytesCached.ToString() + " bytes, expecting " + packetBuilder.TotalBytesExpected.ToString() + " bytes.");

                            //添加数据到 数据包创建器中
                            packetBuilder.AddPartialPacket(totalBytesRead, dataBuffer);
                        }
                    }
                     && (!dataAvailable || ConnectionInfo.ConnectionState == ConnectionState.Shutdown))
                    {
                        //If we read 0 bytes and there is no data available we should be shutting down
                        //如果我们没有读取到数据 应该关闭连接
                        CloseConnection();
                        break;
                    }

                    //If we have read some data and we have more or equal what was expected we attempt a data hand off
                    //如果我们读取到足够的数据(可以解析出一个数据包),对数据进行处理
                     && packetBuilder.TotalBytesCached >= packetBuilder.TotalBytesExpected)
                        IncomingPacketHandleHandOff(packetBuilder);
                }
            }
            //On any error here we close the connection
            //捕捉异常  关闭连接
            catch (NullReferenceException)
            {
                CloseConnection();
            }
            catch (IOException)
            {
                CloseConnection();
            }
            catch (ObjectDisposedException)
            {
                CloseConnection();
            }
            catch (SocketException)
            {
                CloseConnection();
            }
            catch (InvalidOperationException)
            {
                CloseConnection();
            }
            catch (Exception ex)
            {
                LogTools.LogException(ex, "Error_TCPConnectionIncomingPacketHandler");
                CloseConnection();
            }

            //Clear the listen thread object because the thread is about to end
            //清除监听线程 因为线程将关闭
            incomingDataListenThread = null;

            if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("Incoming data listen thread ending for " + ConnectionInfo);
        }

        /// <summary>
        /// Configure the SSL stream from this connection
        /// 配置当期连接上 SSL 数据流
        /// </summary>
        private void ConfigureSSLStream()
        {
            try
            {
                if (ConnectionInfo.ServerSide)
                {
                    connectionStream = new SslStream(tcpClient.GetStream(), false,
                        new RemoteCertificateValidationCallback(CertificateValidationCallback),
                        new LocalCertificateSelectionCallback(CertificateSelectionCallback));

                    ((SslStream)connectionStream).AuthenticateAsServer(SSLOptions.Certificate, SSLOptions.RequireMutualAuthentication, SslProtocols.Default, false);
                }
                else
                {
                    X509CertificateCollection certs = new X509CertificateCollection();

                    if (SSLOptions.Certificate != null) certs.Add(SSLOptions.Certificate);

                    //If we have a certificate set we use that to authenticate
                    connectionStream = new SslStream(tcpClient.GetStream(), false,
                        new RemoteCertificateValidationCallback(CertificateValidationCallback),
                        new LocalCertificateSelectionCallback(CertificateSelectionCallback));

                    ((SslStream)connectionStream).AuthenticateAsClient(SSLOptions.CertificateName, certs, SslProtocols.Default, false);

                }
            }
            catch (AuthenticationException ex)
            {
                throw new ConnectionSetupException("SSL authentication failed. Please check configuration and try again.", ex);
            }

            SSLOptions.Authenticated = true;
        }

        /// <summary>
        /// Callback used to determine if the provided certificate should be accepted
        /// 回调方法 用于确定是否应该接受所提供的证书
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="certificate"></param>
        /// <param name="chain"></param>
        /// <param name="sslPolicyErrors"></param>
        /// <returns></returns>
        private bool CertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            if (sslPolicyErrors == SslPolicyErrors.None)
                return true;
            else if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateNotAvailable && ConnectionInfo.ServerSide)
                //If the client did not provide a remote certificate it may well be because
                //we were not requesting one
                //如果客户没有提供远程认证它很可能是因为我们没有要求
                return !SSLOptions.RequireMutualAuthentication;
            else if (SSLOptions.AllowSelfSignedCertificate && //If we allows self signed certificates we make sure the errors are correct  如果我们允许自签名认证 我们确定这些错误是正确的
                chain.ChainStatus.Length ==  && //Only a single chain error 只是一个单一的链错误
                sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors &&
                chain.ChainStatus[].Status == X509ChainStatusFlags.UntrustedRoot)
            {
                //If we have a local certificate we compare them  如果我们有一个本地的证书 我们比较他们
                if (SSLOptions.Certificate != null)
                    return certificate.Equals(SSLOptions.Certificate);
                else
                    return true;
            }
            else
                return false;
        }

        /// <summary>
        /// Certificate selection callback
        /// 证书选择 回调方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="targetHost"></param>
        /// <param name="localCertificates"></param>
        /// <param name="remoteCertificate"></param>
        /// <param name="acceptableIssuers"></param>
        /// <returns></returns>
        private X509Certificate CertificateSelectionCallback(object sender, string targetHost, X509CertificateCollection localCertificates,
            X509Certificate remoteCertificate, string[] acceptableIssuers)
        {
            return SSLOptions.Certificate;
        }
#endif

        /// <inheritdoc />
        )
        {
#if WINDOWS_PHONE || NETFX_CORE
            //Try to close the socket
            try
            {
                socket.Dispose();
            }
            catch (Exception)
            {
            }
#else
            //The following attempts to correctly close the connection
            //Try to close the networkStream first
            //以下试图正确的关闭连接
            //首先尝试关闭网络流
            try
            {
                if (connectionStream != null) connectionStream.Close();
            }
            catch (Exception)
            {
            }
            finally
            {
                connectionStream = null;
            }

            //Try to close the tcpClient
            //尝试关闭tcpClient对象
            try
            {
                if (tcpClient.Client!=null)
                {
                    tcpClient.Client.Disconnect(false);

#if !ANDROID
                    //Throws uncatchable exception in android
                    //在安卓系统中抛出不可捕捉的异常
                    tcpClient.Client.Close();
#endif
                }
            }
            catch (Exception)
            {
            }

            //Try to close the tcpClient
            //尝试关闭连接
            try
            {
#if !ANDROID
                //Throws uncatchable exception in android
                //在安卓系统中抛出不可捕捉的异常
                tcpClient.Close();
#endif
            }
            catch (Exception)
            {
            }
#endif
        }

        /// <inheritdoc />
        protected override double[] SendStreams(StreamTools.StreamSendWrapper[] streamsToSend, double maxSendTimePerKB, long totalBytesToSend)
        {
            double[] timings = new double[streamsToSend.Length];

            Stream sendingStream;
#if WINDOWS_PHONE || NETFX_CORE
            sendingStream = socket.OutputStream.AsStreamForWrite();
#else
            sendingStream = connectionStream;
#endif

            ; i<streamsToSend.Length; i++)
            {
                )
                {
                    //Write each stream
                    //写入数据流
                    timings[i] = streamsToSend[i].ThreadSafeStream.CopyTo(sendingStream, streamsToSend[i].Start, streamsToSend[i].Length, NetworkComms.SendBufferSizeBytes, maxSendTimePerKB, MinSendTimeoutMS);
                    streamsToSend[i].ThreadSafeStream.Dispose();
                }
                else
                    timings[i] = ;
            }

#if WINDOWS_PHONE || NETFX_CORE
            sendingStream.Flush();
#endif

#if !WINDOWS_PHONE && !NETFX_CORE
            if (!tcpClient.Connected)
            {
                if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Error("TCPClient is not marked as connected after write to networkStream. Possibly indicates a dropped connection.");

                throw new CommunicationException("TCPClient is not marked as connected after write to networkStream. Possibly indicates a dropped connection.");
            }
#endif

            return timings;
        }
    }

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

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

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

  2. 框架-springmvc源码分析(二)

    框架-springmvc源码分析(二) 参考: http://www.cnblogs.com/leftthen/p/5207787.html http://www.cnblogs.com/leftth ...

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

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

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

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

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

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

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

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

  7. ABP源码分析二十六:核心框架中的一些其他功能

    本文是ABP核心项目源码分析的最后一篇,介绍一些前面遗漏的功能 AbpSession AbpSession: 目前这个和CLR的Session没有什么直接的联系.当然可以自定义的去实现IAbpSess ...

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

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

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

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

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

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

随机推荐

  1. Repeater控件使用中的一些小问题

    网页上用来展示列表的数据,发现还是Repeater比GridView,DetailView之类的要灵活些,所以近期用到了就总结下遇到的一些情况,保留下来以备之后查阅,不用现问度娘了... 自己摸索的, ...

  2. GHOST(幽灵)重大漏洞

    cd /usr/local/srcwget https://webshare.uchicago.edu/orgs/ITServices/itsec/Downloads/GHOST.cgcc GHOST ...

  3. DataGridView导出到Excel的三个方法

    #region DataGridView数据显示到Excel /// <summary> /// 打开Excel并将DataGridView控件中数据导出到Excel /// </s ...

  4. 剑指Offer:面试题30——最小的k个数(java实现)

    问题描述: 输入n个整数,找出其中最小的k个数 思路1: 先排序,再取前k个 时间复杂度O(nlogn) 下面给出快排序的代码(基于下面Partition函数的方法) public void Quic ...

  5. UML Sequence sample: if-else

    if (balance >= amount) { ... } else { ... }

  6. linux出现user account has expired解决方案

    SUSE Linux 用户user1登陆不了,确认密码没错,使用root用户登陆,su - user1 提示密码不对,passwd user1提示帐户过期user account hasexpired ...

  7. jmeter上传文件搞了一天,才搞定,没高人帮忙效率就是低,赶紧记下来,以备后用

    先用谷歌浏览器抓包,抓到的包类似这样: 在jmeter里添加一个http请求,配置好参数,方法,端口,路径等, 勾选 在“同请求一起发送参数”里填写上面抓包的部分数据: 分别对应录入,勾选“编码” 我 ...

  8. 【转】Java集合类

    http://blog.csdn.net/zhangerqing/article/details/8122075 http://android.blog.51cto.com/268543/400557 ...

  9. 转 LoadRunner 技巧之THML 与 URL两种录制模式分析

    Loadrunner的Virtual User Generator 提供人脚本的录制功能,对于初学者来说,这大大的降低了编写脚本的门槛,loadrunner提供两种录制脚本的方式:Html_based ...

  10. 微软第四题 给定cost能遍历的最大城市数

    有向图中N*N矩阵 cost:M, 最多可以遍历的结点个数 例如A可以有0->1->2->0->1 代价:2+2+3+2=9<10 输出4 #include <io ...