/// <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; }