首页 > 代码库 > TCPConnection之 TCPConnectionCreat.cs(NetworkComms 2.3.1源码了解和学习)

TCPConnection之 TCPConnectionCreat.cs(NetworkComms 2.3.1源码了解和学习)

networkComms.net2.3.1开源版本,基于gpl V3协议。因为不能公开3.x版本的源码,所以基于此版本进行学习。3.X版本进行了诸多改进和Bug修复,使用方法上两者相差不大。
namespace NetworkCommsDotNet{    public sealed partial class TCPConnection : Connection    {#if WINDOWS_PHONE        /// <summary>        /// The windows phone socket corresponding to this connection.        /// </summary>        StreamSocket socket;#else        /// <summary>        /// 此连接对应的TcpClient        /// </summary>        TcpClient tcpClient;        /// <summary>        /// TcpClient相对应的NetworkStream        /// </summary>        NetworkStream tcpClientNetworkStream;#endif        /// <summary>        /// Create a <see cref="TCPConnection"/> with the provided connectionInfo. If there is an existing connection that will be returned instead.         /// If a new connection is created it will be registered with NetworkComms and can be retreived using <see cref="NetworkComms.GetExistingConnection()"/> and overrides.        /// </summary>        /// <param name="connectionInfo">ConnectionInfo to be used to create connection</param>        /// <param name="establishIfRequired">If true will establish the TCP connection with the remote end point before returning</param>        /// <returns>Returns a <see cref="TCPConnection"/></returns>        public static TCPConnection GetConnection(ConnectionInfo connectionInfo, bool establishIfRequired = true)        {            return GetConnection(connectionInfo, null, null, establishIfRequired);        }        /// <summary>        /// Create a TCP connection with the provided connectionInfo and sets the connection default SendReceiveOptions. If there is an existing connection that is returned instead.        /// If a new connection is created it will be registered with NetworkComms and can be retreived using <see cref="NetworkComms.GetExistingConnection()"/> and overrides.        /// </summary>        /// <param name="connectionInfo">ConnectionInfo to be used to create connection</param>        /// <param name="defaultSendReceiveOptions">The SendReceiveOptions which will be set as this connections defaults</param>        /// <param name="establishIfRequired">If true will establish the TCP connection with the remote end point before returning</param>        /// <returns>Returns a <see cref="TCPConnection"/></returns>        public static TCPConnection GetConnection(ConnectionInfo connectionInfo, SendReceiveOptions defaultSendReceiveOptions, bool establishIfRequired = true)        {            return GetConnection(connectionInfo, defaultSendReceiveOptions, null, establishIfRequired);        }        /// <summary>        /// Internal <see cref="TCPConnection"/> creation which hides the necessary internal calls        /// </summary>        /// <param name="connectionInfo">ConnectionInfo to be used to create connection</param>        /// <param name="defaultSendReceiveOptions">Connection default SendReceiveOptions</param>        /// <param name="tcpClient">If this is an incoming connection we will already have access to the tcpClient, otherwise use null</param>        /// <param name="establishIfRequired">Establish during create if true</param>        /// <returns>An existing connection or a new one</returns>#if WINDOWS_PHONE        internal static TCPConnection GetConnection(ConnectionInfo connectionInfo, SendReceiveOptions defaultSendReceiveOptions, StreamSocket socket, bool establishIfRequired = true)#else        internal static TCPConnection GetConnection(ConnectionInfo connectionInfo, SendReceiveOptions defaultSendReceiveOptions, TcpClient tcpClient, bool establishIfRequired = true)#endif        {            connectionInfo.ConnectionType = ConnectionType.TCP;            //If we have a tcpClient at this stage we must be serverside#if WINDOWS_PHONE             if (socket != null) connectionInfo.ServerSide = true;#else            if (tcpClient != null) connectionInfo.ServerSide = true;#endif            bool newConnection = false;            TCPConnection connection;            lock (NetworkComms.globalDictAndDelegateLocker)            {                //Check to see if a conneciton already exists, if it does return that connection, if not return a new one                if (NetworkComms.ConnectionExists(connectionInfo.RemoteEndPoint, connectionInfo.ConnectionType))                {                    if (NetworkComms.LoggingEnabled)                        NetworkComms.Logger.Trace("Attempted to create new TCPConnection to connectionInfo=‘" + connectionInfo + "‘ but there is an existing connection. Existing connection will be returned instead.");                    establishIfRequired = false;                    connection = (TCPConnection)NetworkComms.GetExistingConnection(connectionInfo.RemoteEndPoint, connectionInfo.ConnectionType);                }                else                {                    if (NetworkComms.LoggingEnabled)                        NetworkComms.Logger.Trace("Creating new TCPConnection to connectionInfo=‘" + connectionInfo + "‘." + (establishIfRequired ? " Connection will be established." : " Connection will not be established."));                    if (connectionInfo.ConnectionState == ConnectionState.Establishing)                        throw new ConnectionSetupException("Connection state for connection " + connectionInfo + " is marked as establishing. This should only be the case here due to a bug.");                    //If an existing connection does not exist but the info we are using suggests it should we need to reset the info                    //so that it can be reused correctly. This case generally happens when using Comms in the format                     //TCPConnection.GetConnection(info).SendObject(packetType, objToSend);                    if (connectionInfo.ConnectionState == ConnectionState.Established || connectionInfo.ConnectionState == ConnectionState.Shutdown)                        connectionInfo.ResetConnectionInfo();                    //We add a reference to networkComms for this connection within the constructor#if WINDOWS_PHONE                    connection = new TCPConnection(connectionInfo, defaultSendReceiveOptions, socket);#else                    connection = new TCPConnection(connectionInfo, defaultSendReceiveOptions, tcpClient);#endif                    newConnection = true;                }            }            if (newConnection && establishIfRequired) connection.EstablishConnection();             else if (!newConnection) connection.WaitForConnectionEstablish(NetworkComms.ConnectionEstablishTimeoutMS);            if (!NetworkComms.commsShutdown) TriggerConnectionKeepAliveThread();            return connection;        }        /// <summary>        /// TCP connection constructor        /// </summary>#if WINDOWS_PHONE        private TCPConnection(ConnectionInfo connectionInfo, SendReceiveOptions defaultSendReceiveOptions, StreamSocket socket)#else        private TCPConnection(ConnectionInfo connectionInfo, SendReceiveOptions defaultSendReceiveOptions, TcpClient tcpClient)#endif            : base(connectionInfo, defaultSendReceiveOptions)        {            //We don‘t guarantee that the tcpClient has been created yet#if WINDOWS_PHONE            if (socket != null) this.socket = socket;#else            if (tcpClient != null) this.tcpClient = tcpClient;#endif          }        /// <summary>        /// Establish the connection        /// </summary>        protected override void EstablishConnectionSpecific()        {#if WINDOWS_PHONE            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.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.UpdateLocalEndPointInfo((IPEndPoint)tcpClient.Client.LocalEndPoint);            //We are going to be using the networkStream quite a bit so we pull out a reference once here            tcpClientNetworkStream = tcpClient.GetStream();            //When we tell the socket/client to close we want it to do so immediately            //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            //NOTE: This did not seem to work reliably so was replaced with the keepAlive packet feature            //this.tcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);            tcpClient.ReceiveBufferSize = NetworkComms.ReceiveBufferSizeBytes;            tcpClient.SendBufferSize = NetworkComms.SendBufferSizeBytes;            //This disables the ‘nagle alogrithm‘            //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            tcpClient.NoDelay = true;            tcpClient.Client.NoDelay = true;#endif            //Start listening for incoming data            StartIncomingDataListen();            //Get a list of existing listeners            List<IPEndPoint> existingListeners = TCPConnection.ExistingLocalListenEndPoints(ConnectionInfo.LocalEndPoint.Address);            //Select a listener for this connection            IPEndPoint selectedExistingListener = null;            if (existingListeners.Count > 0)                selectedExistingListener = (existingListeners.Contains(ConnectionInfo.LocalEndPoint) ? ConnectionInfo.LocalEndPoint : existingListeners[0]);            //If we are server side and we have just received an incoming connection we need to return a conneciton id            //This id will be used in all future connections from this machine            if (ConnectionInfo.ServerSide)            {                if (selectedExistingListener == null) throw new ConnectionSetupException("Detected a server side connection when an existing listener was not present.");                if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Debug("Waiting for client connnectionInfo from " + ConnectionInfo);                //Wait for the client to send its identification                if (!connectionSetupWait.WaitOne(NetworkComms.ConnectionEstablishTimeoutMS))                    throw new ConnectionSetupException("Timeout waiting for client connectionInfo with " + ConnectionInfo + ". Connection created at " + ConnectionInfo.ConnectionCreationTime.ToString("HH:mm:ss.fff") + ", its now " + DateTime.Now.ToString("HH:mm:ss.f"));                if (connectionSetupException)                {                    if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Debug("Connection setup exception. ServerSide with " + ConnectionInfo + ", " + connectionSetupExceptionStr);                    throw new ConnectionSetupException("ServerSide. " + connectionSetupExceptionStr);                }                //Trigger the connection establish delegates before replying to the connection establish                 base.EstablishConnectionSpecific();                //Once we have the clients id we send our own                SendObject(Enum.GetName(typeof(ReservedPacketType), ReservedPacketType.ConnectionSetup), new ConnectionInfo(ConnectionType.TCP, NetworkComms.NetworkIdentifier, new IPEndPoint(ConnectionInfo.RemoteEndPoint.Address, selectedExistingListener.Port), true), NetworkComms.InternalFixedSendReceiveOptions);            }            else            {                if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Debug("Sending connnectionInfo to " + ConnectionInfo);                //As the client we initiated the connection we now forward our local node identifier to the server                //If we are listening we include our local listen port as well                SendObject(Enum.GetName(typeof(ReservedPacketType), ReservedPacketType.ConnectionSetup), new ConnectionInfo(ConnectionType.TCP, NetworkComms.NetworkIdentifier, new IPEndPoint(ConnectionInfo.RemoteEndPoint.Address, (selectedExistingListener != null ? selectedExistingListener.Port : ConnectionInfo.LocalEndPoint.Port)), selectedExistingListener != null), NetworkComms.InternalFixedSendReceiveOptions);                //Wait here for the server end to return its own identifier                if (!connectionSetupWait.WaitOne(NetworkComms.ConnectionEstablishTimeoutMS))                    throw new ConnectionSetupException("Timeout waiting for server connnectionInfo from " + ConnectionInfo + ". Connection created at " + ConnectionInfo.ConnectionCreationTime.ToString("HH:mm:ss.fff") + ", its now " + DateTime.Now.ToString("HH:mm:ss.f"));                //If we are client side we can update the localEndPoint for this connection to reflect what the remote end might see if we are also listening                if (selectedExistingListener != null) ConnectionInfo.UpdateLocalEndPointInfo(selectedExistingListener);                if (connectionSetupException)                {                    if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Debug("Connection setup exception. ClientSide with " + ConnectionInfo + ", " + connectionSetupExceptionStr);                    throw new ConnectionSetupException("ClientSide. " + connectionSetupExceptionStr);                }                //Trigger the connection establish delegates once the server has replied to the connection establish                base.EstablishConnectionSpecific();            }#if !WINDOWS_PHONE            //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            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        /// </summary>        private void ConnectSocket()        {            try            {                if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("Connecting TCP client with " + ConnectionInfo);                bool connectSuccess = true;#if WINDOWS_PHONE                //We now connect to our target                socket = new StreamSocket();                socket.Control.NoDelay = EnableNagleAlgorithmForNewConnections;                CancellationTokenSource cancelAfterTimeoutToken = new CancellationTokenSource(NetworkComms.ConnectionEstablishTimeoutMS);                try                {                    if (ConnectionInfo.LocalEndPoint != null)                    {                        var endpointPairForConnection = new Windows.Networking.EndpointPair(new Windows.Networking.HostName(ConnectionInfo.LocalEndPoint.Address.ToString()), ConnectionInfo.LocalEndPoint.Port.ToString(),                                                        new Windows.Networking.HostName(ConnectionInfo.RemoteEndPoint.Address.ToString()), ConnectionInfo.RemoteEndPoint.Port.ToString());                        var task = socket.ConnectAsync(endpointPairForConnection).AsTask(cancelAfterTimeoutToken.Token);                        task.Wait();                    }                    else                    {                        var task = socket.ConnectAsync(new Windows.Networking.HostName(ConnectionInfo.RemoteEndPoint.Address.ToString()), ConnectionInfo.RemoteEndPoint.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 asyn version                //This allows us to choose our own connection establish timeout                IAsyncResult ar = tcpClient.BeginConnect(ConnectionInfo.RemoteEndPoint.Address, ConnectionInfo.RemoteEndPoint.Port, null, null);                WaitHandle connectionWait = ar.AsyncWaitHandle;                try                {                    if (!ar.AsyncWaitHandle.WaitOne(NetworkComms.ConnectionEstablishTimeoutMS, false))                    {                        tcpClient.Close();                        connectSuccess = false;                    }                    tcpClient.EndConnect(ar);                }                finally                {                    connectionWait.Close();                }#endif                if (!connectSuccess) throw new ConnectionSetupException("Timeout waiting for remoteEndPoint to accept TCP connection.");            }            catch (Exception ex)            {                CloseConnection(true, 17);                throw new ConnectionSetupException("Error during TCP connection establish with destination (" + ConnectionInfo + "). Destination may not be listening or connect timed out. " + ex.ToString());            }        }        /// <summary>        /// Starts listening for incoming data on this TCP connection        /// </summary>        protected override void StartIncomingDataListen()        {            if (!NetworkComms.ConnectionExists(ConnectionInfo.RemoteEndPoint, ConnectionType.TCP))            {                CloseConnection(true, 18);                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, 0, dataBuffer.Length, new AsyncCallback(IncomingTCPPacketHandler), stream);   #else            lock (delegateLocker)            {                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 = "IncomingDataListener";                        incomingDataListenThread.Start();                    }                }                else                    tcpClientNetworkStream.BeginRead(dataBuffer, 0, dataBuffer.Length, new AsyncCallback(IncomingTCPPacketHandler), tcpClientNetworkStream);            }#endif            if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("Listening for incoming data from " + ConnectionInfo);        }    }}
来自英国剑桥的c#网络通讯框架  开源版本: networkcomms2.3.1  可以进入此页面下载 networkcomms网络通讯框架学习 

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

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

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

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

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

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

 

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

TCPConnection之 TCPConnectionCreat.cs(NetworkComms 2.3.1源码了解和学习)