/// <summary> /// Called to bind to socket and start heartbeat thread. /// The socket will be bound to listen on any network interface unless the <see cref="NetConfiguration.Address"/> explicitly specifies an interface. /// </summary> public void Start() { if (m_isBound) { return; } // TODO: this check should be done somewhere earlier, in uLink preferably. if (m_config.StartPort > m_config.EndPort) { throw new NetException("The start port (" + m_config.StartPort + ") must be less or equal to the end port (" + m_config.EndPort + ")"); } //by WuNan @2016/09/28 14:26:22 var bindIP = String.IsNullOrEmpty(m_config.AddressStr) ? #if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR (uLink.NetworkUtility.IsSupportIPv6() ? IPAddress.IPv6Any : IPAddress.Any) : NetUtility.Resolve(m_config.AddressStr); #else IPAddress.Any : NetUtility.Resolve(m_config.AddressStr); #endif Log.Debug(LogFlags.Socket, "Creating non-blocking UDP socket"); var sock = NetworkSocket.Create(m_config.SocketType); Log.Debug(LogFlags.Socket, "Successfully created Socket"); for (int port = m_config.StartPort; port <= m_config.EndPort; port++) { try { sock.Bind(new NetworkEndPoint(bindIP, port)); m_isBound = true; break; } catch (SocketException ex) { Log.Debug(LogFlags.Socket, "Failed to bind to specific port ", port, ": ", ex); if (port == m_config.EndPort) { try { sock.Close(0); } catch { } throw new NetException("Failed to bind to port range " + m_config.StartPort + "-" + m_config.EndPort, ex); } } } m_socket = sock; LogWrite("Listening on " + m_socket.listenEndPoint); if (m_config.ReceiveBufferSize != 0) { try { m_socket.receiveBufferSize = m_config.ReceiveBufferSize; m_config.ReceiveBufferSize = m_socket.receiveBufferSize; // make sure we have the actual size } catch (Exception ex) { Log.Warning(LogFlags.Socket, "Unable to set socket ", SocketOptionName.ReceiveBuffer, " size to ", m_config.ReceiveBufferSize, ": ", ex); } } else { try { m_config.ReceiveBufferSize = m_socket.receiveBufferSize; Log.Debug(LogFlags.Socket, "Socket ", SocketOptionName.ReceiveBuffer, " is set to OS-specific default ", m_config.ReceiveBufferSize); } catch (Exception ex) { Log.Warning(LogFlags.Socket, "Unable to get socket ", SocketOptionName.ReceiveBuffer, ": ", ex); } } if (m_config.SendBufferSize != 0) { try { m_socket.sendBufferSize = m_config.SendBufferSize; m_config.SendBufferSize = m_socket.sendBufferSize; // make sure we have the actual size } catch (Exception ex) { Log.Warning(LogFlags.Socket, "Unable to set socket ", SocketOptionName.SendBuffer, " size to ", m_config.SendBufferSize, ": ", ex); } } else { try { m_config.SendBufferSize = m_socket.sendBufferSize; Log.Debug(LogFlags.Socket, "Socket ", SocketOptionName.SendBuffer, " is set to OS-specific default ", m_config.SendBufferSize); } catch (Exception ex) { Log.Warning(LogFlags.Socket, "Unable to get socket ", SocketOptionName.SendBuffer, ": ", ex); } } m_receiveBuffer.EnsureBufferSizeInBytes(m_config.ReceiveBufferSize); m_sendBuffer.EnsureBufferSizeInBytes(m_config.SendBufferSize); // TODO: ugly hack to determine if server if (this is NetServer) { m_socket.Listen(m_config.MaxConnections); } // display simulated networking conditions in debug log if (m_simulatedLoss > 0.0f) { LogWrite("Simulating " + (m_simulatedLoss * 100.0f) + "% loss"); } if (m_simulatedMinimumLatency > 0.0f || m_simulatedLatencyVariance > 0.0f) { LogWrite("Simulating " + ((int)(m_simulatedMinimumLatency * 1000.0f)) + " - " + NetTime.ToMillis(m_simulatedMinimumLatency + m_simulatedLatencyVariance) + " ms roundtrip latency"); } if (m_simulatedDuplicateChance > 0.0f) { LogWrite("Simulating " + (m_simulatedDuplicateChance * 100.0f) + "% chance of packet duplication"); } if (m_config.m_throttleBytesPerSecond > 0) { LogWrite("Throttling to " + m_config.m_throttleBytesPerSecond + " bytes per second"); } m_isBound = true; m_shutdownComplete = false; m_statistics.Reset(); }