Beispiel #1
0
        /// <summary>
        /// This will begin the connection for TCP, this is a thread blocking operation until the connection
        /// is either established or has failed
        /// </summary>
        /// <param name="hostAddress">[127.0.0.1] Ip Address to host from</param>
        /// <param name="port">[15937] Port to allow connections from</param>
        public void Connect(string hostAddress = "0.0.0.0", ushort port = DEFAULT_PORT)
        {
            if (string.IsNullOrEmpty(hostAddress))
            {
                throw new BaseNetworkException("An ip address must be specified to bind to. If you are unsure, you can set to 127.0.0.1");
            }

            // Check to see if this server is being bound to a "loopback" address, if so then bind to any, otherwise bind to specified address
            if (hostAddress == "0.0.0.0" || hostAddress == "localhost")
            {
                ipAddress = IPAddress.Any;
            }
            else
            {
                ipAddress = IPAddress.Parse(hostAddress);
            }

            try
            {
                // Setup and start the base C# TcpListner
                listener = new TcpListener(ipAddress, port);
                //listener.Start();

                Me = new NetworkingPlayer(ServerPlayerCounter++, "0.0.0.0", true, listener, this);
                Me.InstanceGuid = InstanceGuid.ToString();

                // Create the thread that will be listening for clients and start its execution
                //Thread connectionThread = new Thread(new ThreadStart(ListenForConnections));
                //connectionThread.Start();
                //Task.Queue(ListenForConnections);
                listener.Start();
                listener.BeginAcceptTcpClient(ListenForConnections, listener);

                // Create the thread that will be listening for new data from connected clients and start its execution
                Task.Queue(ReadClients);

                // Create the thread that will check for player timeouts
                Task.Queue(CheckClientTimeout);

                // Do any generic initialization in result of the successful bind
                OnBindSuccessful();

                //Let myself know I connected successfully
                OnPlayerConnected(Me);
                // Set myself as a connected client
                Me.Connected = true;

                //Set the port
                SetPort((ushort)((IPEndPoint)listener.LocalEndpoint).Port);
            }
            catch (Exception e)
            {
                Logging.BMSLog.LogException(e);
                // Do any generic initialization in result of the binding failure
                OnBindFailure();

                throw new FailedBindingException("Failed to bind to host/port, see inner exception", e);
            }
        }
        /// <summary>
        /// This will begin the connection for TCP, this is a thread blocking operation until the connection
        /// is either established or has failed
        /// </summary>
        /// <param name="hostAddress">[127.0.0.1] Ip Address to host from</param>
        /// <param name="port">[15937] Port to allow connections from</param>
        public void Connect(string hostAddress = "0.0.0.0", ushort port = DEFAULT_PORT)
        {
            if (Disposed)
            {
                throw new ObjectDisposedException("TCPServer", "This object has been disposed and can not be used to connect, please use a new TCPServer");
            }

            if (string.IsNullOrEmpty(hostAddress))
            {
                throw new BaseNetworkException("An ip address must be specified to bind to. If you are unsure, you can set to 127.0.0.1");
            }

            // Check to see if this server is being bound to a "loopback" address, if so then bind to any, otherwise bind to specified address
            if (hostAddress == "0.0.0.0" || hostAddress == "localhost")
            {
                ipAddress = IPAddress.Any;
            }
            else
            {
                ipAddress = IPAddress.Parse(hostAddress);
            }

            try
            {
                // Setup and start the base C# TcpListner
                listener = new TcpListener(ipAddress, port);
                //listener.Start();

                Me = new NetworkingPlayer(ServerPlayerCounter++, "0.0.0.0", true, listener, this);
                Me.InstanceGuid = InstanceGuid.ToString();

                // Create the thread that will be listening for clients and start its execution
                //Thread connectionThread = new Thread(new ThreadStart(ListenForConnections));
                //connectionThread.Start();
                //Task.Queue(ListenForConnections);
                listener.Start();
                listener.BeginAcceptTcpClient(ListenForConnections, listener);

                //在成功绑定的结果中执行任何通用初始化
                // Do any generic initialization in result of the successful bind
                OnBindSuccessful();

                //创建将监听来自连接客户端的新数据并开始执行的线程
                // Create the thread that will be listening for new data from connected clients and start its execution
                Task.Queue(ReadClients);

                // 创建将检查播放器超时的线程
                // Create the thread that will check for player timeouts
                Task.Queue(() =>
                {
                    // TODO ZF 关闭检测超时
                    //commonServerLogic.CheckClientTimeout((player) =>
                    //{
                    //    Disconnect(player, true);
                    //    OnPlayerTimeout(player);
                    //    CleanupDisconnections();
                    //});
                });

                //让我知道我连接成功
                //Let myself know I connected successfully
                OnPlayerConnected(Me);
                //将自己设置为连接的客户端
                // Set myself as a connected client
                Me.Connected = true;

                //设置端口
                //Set the port
                SetPort((ushort)((IPEndPoint)listener.LocalEndpoint).Port);
            }
            catch (Exception e)
            {
                BMSLog.LogException(e);
                // Do any generic initialization in result of the binding failure
                OnBindFailure();

                throw new FailedBindingException("Failed to bind to host/port, see inner exception", e);
            }
        }
        /// <summary>
        /// Async method for handling up new incoming TCP connections
        /// </summary>
        private void TCPConnectionReceivedAsync(IAsyncResult ar)
        {
            if (!IsListening)
            {
                return;
            }

            try
            {
                TcpClient      newTCPClient      = listenerInstance.EndAcceptTcpClient(ar);
                ConnectionInfo newConnectionInfo = new ConnectionInfo(ConnectionType.TCP, (IPEndPoint)newTCPClient.Client.RemoteEndPoint, (IPEndPoint)newTCPClient.Client.LocalEndPoint, ApplicationLayerProtocol, this);

                if (NetworkComms.LoggingEnabled)
                {
                    NetworkComms.Logger.Info("New incoming TCP connection from " + newConnectionInfo);
                }

                //We have to use our own thread pool here as the performance of the .Net one is awful
                NetworkComms.IncomingConnectionEstablishThreadPool.EnqueueItem(QueueItemPriority.Normal, new WaitCallback((obj) =>
                {
                    #region Pickup The New Connection

                    try
                    {
                        TCPConnection.GetConnection(newConnectionInfo, ListenerDefaultSendReceiveOptions, newTCPClient, true, SSLOptions);
                    }
                    catch (ConfirmationTimeoutException)
                    {
                        //If this exception gets thrown its generally just a client closing a connection almost immediately after creation
                    }
                    catch (CommunicationException)
                    {
                        //If this exception gets thrown its generally just a client closing a connection almost immediately after creation
                    }
                    catch (ConnectionSetupException)
                    {
                        //If we are the server end and we did not pick the incoming connection up then tooo bad!
                    }
                    catch (SocketException)
                    {
                        //If this exception gets thrown its generally just a client closing a connection almost immediately after creation
                    }
                    catch (Exception ex)
                    {
                        //For some odd reason SocketExceptions don't always get caught above, so another check
                        if (ex.GetBaseException().GetType() != typeof(SocketException))
                        {
                            //Can we catch the socketException by looking at the string error text?
                            if (ex.ToString().StartsWith("System.Net.Sockets.SocketException"))
                            {
                                LogTools.LogException(ex, "ConnectionSetupError_SE");
                            }
                            else
                            {
                                LogTools.LogException(ex, "ConnectionSetupError");
                            }
                        }
                    }

                    #endregion Pickup The New Connection
                }), null);
            }
            catch (SocketException)
            {
                //If this exception gets thrown its generally just a client closing a connection almost immediately after creation
            }
            catch (Exception ex)
            {
                //For some odd reason SocketExceptions don't always get caught above, so another check
                if (ex.GetBaseException().GetType() != typeof(SocketException))
                {
                    //Can we catch the socketException by looking at the string error text?
                    if (ex.ToString().StartsWith("System.Net.Sockets.SocketException"))
                    {
                        LogTools.LogException(ex, "ConnectionSetupError_SE");
                    }
                    else
                    {
                        LogTools.LogException(ex, "ConnectionSetupError");
                    }
                }
            }
            finally
            {
                listenerInstance.BeginAcceptTcpClient(TCPConnectionReceivedAsync, null);
            }
        }
        /// <inheritdoc />
        internal override void StartListening(EndPoint desiredLocalListenEndPoint, bool useRandomPortFailOver)
        {
            if (desiredLocalListenEndPoint.GetType() != typeof(IPEndPoint))
            {
                throw new ArgumentException("Invalid desiredLocalListenEndPoint type provided.", "desiredLocalListenEndPoint");
            }
            if (IsListening)
            {
                throw new InvalidOperationException("Attempted to call StartListening when already listening.");
            }

            IPEndPoint desiredLocalListenIPEndPoint = (IPEndPoint)desiredLocalListenEndPoint;

            try
            {
#if WINDOWS_PHONE || NETFX_CORE
                listenerInstance = new StreamSocketListener();
                listenerInstance.ConnectionReceived += newListenerInstance_ConnectionReceived;
                listenerInstance.BindEndpointAsync(new Windows.Networking.HostName(desiredLocalListenIPEndPoint.Address.ToString()), desiredLocalListenIPEndPoint.Port.ToString()).AsTask().Wait();
#else
                listenerInstance = new TcpListener(desiredLocalListenIPEndPoint);
                listenerInstance.Start();
                listenerInstance.BeginAcceptTcpClient(TCPConnectionReceivedAsync, null);
#endif
            }
            catch (SocketException)
            {
                //If the port we wanted is not available
                if (useRandomPortFailOver)
                {
                    try
                    {
#if WINDOWS_PHONE || NETFX_CORE
                        listenerInstance.BindEndpointAsync(new Windows.Networking.HostName(desiredLocalListenIPEndPoint.Address.ToString()), "").AsTask().Wait();
#else
                        listenerInstance = new TcpListener(desiredLocalListenIPEndPoint.Address, 0);
                        listenerInstance.Start();
                        listenerInstance.BeginAcceptTcpClient(TCPConnectionReceivedAsync, null);
#endif
                    }
                    catch (SocketException)
                    {
                        //If we get another socket exception this appears to be a bad IP. We will just ignore this IP
                        if (NetworkComms.LoggingEnabled)
                        {
                            NetworkComms.Logger.Error("It was not possible to open a random port on " + desiredLocalListenIPEndPoint.Address + ". This endPoint may not support listening or possibly try again using a different port.");
                        }
                        throw new CommsSetupShutdownException("It was not possible to open a random port on " + desiredLocalListenIPEndPoint.Address + ". This endPoint may not support listening or possibly try again using a different port.");
                    }
                }
                else
                {
                    if (NetworkComms.LoggingEnabled)
                    {
                        NetworkComms.Logger.Error("It was not possible to open port #" + desiredLocalListenIPEndPoint.Port.ToString() + " on " + desiredLocalListenIPEndPoint.Address + ". This endPoint may not support listening or possibly try again using a different port.");
                    }
                    throw new CommsSetupShutdownException("It was not possible to open port #" + desiredLocalListenIPEndPoint.Port.ToString() + " on " + desiredLocalListenIPEndPoint.Address + ". This endPoint may not support listening or possibly try again using a different port.");
                }
            }

#if WINDOWS_PHONE || NETFX_CORE
            this.LocalListenEndPoint = new IPEndPoint(desiredLocalListenIPEndPoint.Address, int.Parse(listenerInstance.Information.LocalPort));
#else
            this.LocalListenEndPoint = (IPEndPoint)listenerInstance.LocalEndpoint;
#endif
            this.IsListening = true;
        }