提交
This commit is contained in:
@@ -7,20 +7,24 @@ using SGModule.Common.Helper;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
namespace SGModule.Net {
|
||||
public enum ConnectionStatus {
|
||||
namespace SGModule.Net
|
||||
{
|
||||
public enum ConnectionStatus
|
||||
{
|
||||
Uninitialized, // 未初始化
|
||||
Connected, // 已连接
|
||||
Disconnected // 未连接
|
||||
}
|
||||
|
||||
// 网络检测类
|
||||
public class NetChecker : SingletonMonoBehaviour<NetChecker> {
|
||||
public class NetChecker : SingletonMonoBehaviour<NetChecker>
|
||||
{
|
||||
private const float WebRequestInterval = 5f;
|
||||
private const float PingInterval = 2;
|
||||
|
||||
// 可配置多个检测 URL
|
||||
[SerializeField] private List<string> checkUrls = new() {
|
||||
[SerializeField]
|
||||
private List<string> checkUrls = new() {
|
||||
"https://www.baidu.com", // 国内 URL
|
||||
"https://www.google.com" // 国外 URL
|
||||
};
|
||||
@@ -45,16 +49,19 @@ namespace SGModule.Net {
|
||||
/// <summary>
|
||||
/// null = 未检测;true = 联网;false = 未联网
|
||||
/// </summary>
|
||||
private bool? IsConnected {
|
||||
private bool? IsConnected
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private void OnEnable() {
|
||||
private void OnEnable()
|
||||
{
|
||||
StartCheckingInternet();
|
||||
}
|
||||
|
||||
private void OnDisable() {
|
||||
private void OnDisable()
|
||||
{
|
||||
StopCheckingInternet();
|
||||
}
|
||||
|
||||
@@ -64,69 +71,84 @@ namespace SGModule.Net {
|
||||
/// <param name="timeout">最多等待的总时间(秒)</param>
|
||||
/// <param name="checkInterval">每次重试间隔</param>
|
||||
/// <param name="callback">检测结果回调</param>
|
||||
public IEnumerator WaitUntilNetworkConnected(float timeout, float checkInterval, Action<bool> callback) {
|
||||
public IEnumerator WaitUntilNetworkConnected(float timeout, float checkInterval, Action<bool> callback)
|
||||
{
|
||||
var elapsed = 0f;
|
||||
|
||||
// 阶段 1: 等待初始化完成
|
||||
while (!IsConnected.HasValue && elapsed < timeout) {
|
||||
while (!IsConnected.HasValue && elapsed < timeout)
|
||||
{
|
||||
yield return new WaitForSeconds(checkInterval);
|
||||
elapsed += checkInterval;
|
||||
}
|
||||
|
||||
if (!IsConnected.HasValue) {
|
||||
if (!IsConnected.HasValue)
|
||||
{
|
||||
Log.Net.Warning("网络检测初始化超时!");
|
||||
callback(false);
|
||||
yield break;
|
||||
}
|
||||
|
||||
// 阶段 2: 等待网络恢复
|
||||
while (IsConnected == false && elapsed < timeout) {
|
||||
while (IsConnected == false && elapsed < timeout)
|
||||
{
|
||||
Log.Net.Warning($"网络异常,等待中... 已耗时: {elapsed:F1}s");
|
||||
yield return new WaitForSeconds(checkInterval);
|
||||
elapsed += checkInterval;
|
||||
}
|
||||
|
||||
var success = IsConnected == true;
|
||||
if (!success) {
|
||||
if (!success)
|
||||
{
|
||||
Log.Net.Warning("网络连接等待超时!");
|
||||
}
|
||||
|
||||
callback(success);
|
||||
}
|
||||
|
||||
public ConnectionStatus GetConnectionStatus() {
|
||||
return IsConnected switch {
|
||||
public ConnectionStatus GetConnectionStatus()
|
||||
{
|
||||
return IsConnected switch
|
||||
{
|
||||
null => ConnectionStatus.Uninitialized,
|
||||
true => ConnectionStatus.Connected,
|
||||
false => ConnectionStatus.Disconnected
|
||||
};
|
||||
}
|
||||
|
||||
public void Init() {
|
||||
public void Init()
|
||||
{
|
||||
StartCheckingInternet();
|
||||
}
|
||||
|
||||
private void StartCheckingInternet() {
|
||||
private void StartCheckingInternet()
|
||||
{
|
||||
_checkInterval = usePingCheck ? PingInterval : WebRequestInterval;
|
||||
_checkInternetCoroutine ??= StartCoroutine(CheckInternetRoutine());
|
||||
}
|
||||
|
||||
private void StopCheckingInternet() {
|
||||
if (_checkInternetCoroutine != null) {
|
||||
private void StopCheckingInternet()
|
||||
{
|
||||
if (_checkInternetCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_checkInternetCoroutine);
|
||||
_checkInternetCoroutine = null;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator CheckInternetRoutine() {
|
||||
while (true) {
|
||||
if (_isChecking) {
|
||||
private IEnumerator CheckInternetRoutine()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (_isChecking)
|
||||
{
|
||||
yield break; // 避免并发冲突
|
||||
}
|
||||
|
||||
_isChecking = true;
|
||||
|
||||
if (QuickNetDeviceCheck()) {
|
||||
if (QuickNetDeviceCheck())
|
||||
{
|
||||
// if (usePingCheck) {
|
||||
yield return CheckWithPing();
|
||||
// }
|
||||
@@ -134,11 +156,13 @@ namespace SGModule.Net {
|
||||
// yield return CheckWithUnityWebRequest();
|
||||
// }
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
IsConnected = false;
|
||||
}
|
||||
|
||||
if (IsConnected.HasValue && _lastConnected != IsConnected.Value) {
|
||||
if (IsConnected.HasValue && _lastConnected != IsConnected.Value)
|
||||
{
|
||||
Log.Net.Info($"网络状态变化: {IsConnected}");
|
||||
_lastConnected = IsConnected.Value;
|
||||
}
|
||||
@@ -151,42 +175,46 @@ namespace SGModule.Net {
|
||||
/// <summary>
|
||||
/// 使用 Ping 检测网络连通性
|
||||
/// </summary>
|
||||
private IEnumerator CheckWithPing() {
|
||||
private IEnumerator CheckWithPing()
|
||||
{
|
||||
var pings = _pingAddresses.Select(ip => new Ping(ip)).ToList();
|
||||
|
||||
var startTime = Time.realtimeSinceStartup;
|
||||
var success = false;
|
||||
|
||||
// 等待所有 Ping 返回结果或超时
|
||||
while (Time.realtimeSinceStartup - startTime < _checkInterval) {
|
||||
foreach (var ping in pings) {
|
||||
if (ping.isDone && ping.time >= 0) {
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// // 等待所有 Ping 返回结果或超时
|
||||
// while (Time.realtimeSinceStartup - startTime < _checkInterval) {
|
||||
// foreach (var ping in pings) {
|
||||
// if (ping.isDone && ping.time >= 0) {
|
||||
// success = true;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
if (success) {
|
||||
break;
|
||||
}
|
||||
// if (success) {
|
||||
// break;
|
||||
// }
|
||||
|
||||
yield return new WaitForSecondsRealtime(0.1f);
|
||||
}
|
||||
|
||||
// }
|
||||
yield return new WaitForSecondsRealtime(0.1f);
|
||||
// 如果有任意一个 Ping 成功,网络即为可用
|
||||
IsConnected = success;
|
||||
IsConnected = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用 UnityWebRequest 检测网络连通性
|
||||
/// </summary>
|
||||
private IEnumerator CheckWithUnityWebRequest() {
|
||||
if (!string.IsNullOrEmpty(_preferredUrl)) {
|
||||
private IEnumerator CheckWithUnityWebRequest()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_preferredUrl))
|
||||
{
|
||||
var request = UnityWebRequest.Get(_preferredUrl);
|
||||
request.timeout = (int) _checkInterval;
|
||||
request.timeout = (int)_checkInterval;
|
||||
yield return request.SendWebRequest();
|
||||
|
||||
if (request.result == UnityWebRequest.Result.Success) {
|
||||
if (request.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
IsConnected = true;
|
||||
request.Dispose();
|
||||
yield break;
|
||||
@@ -202,25 +230,30 @@ namespace SGModule.Net {
|
||||
var ops = new List<UnityWebRequestAsyncOperation>();
|
||||
var requests = new List<UnityWebRequest>();
|
||||
|
||||
foreach (var url in checkUrls) {
|
||||
foreach (var url in checkUrls)
|
||||
{
|
||||
var req = UnityWebRequest.Get(url);
|
||||
req.timeout = (int) _checkInterval;
|
||||
req.timeout = (int)_checkInterval;
|
||||
ops.Add(req.SendWebRequest());
|
||||
requests.Add(req);
|
||||
}
|
||||
|
||||
yield return StartCoroutine(WaitForAnyRequest(ops));
|
||||
|
||||
foreach (var req in requests) {
|
||||
foreach (var req in requests)
|
||||
{
|
||||
req.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 等待任意一个请求完成并返回
|
||||
private IEnumerator WaitForAnyRequest(List<UnityWebRequestAsyncOperation> ops) {
|
||||
while (ops.Any(op => !op.isDone)) {
|
||||
if (ops.Any(op => op.isDone && op.webRequest.result == UnityWebRequest.Result.Success)) {
|
||||
private IEnumerator WaitForAnyRequest(List<UnityWebRequestAsyncOperation> ops)
|
||||
{
|
||||
while (ops.Any(op => !op.isDone))
|
||||
{
|
||||
if (ops.Any(op => op.isDone && op.webRequest.result == UnityWebRequest.Result.Success))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -229,8 +262,10 @@ namespace SGModule.Net {
|
||||
|
||||
var successOp = ops.FirstOrDefault(op => op.webRequest.result == UnityWebRequest.Result.Success);
|
||||
|
||||
if (successOp == null) {
|
||||
foreach (var op in ops.Where(op => op.isDone)) {
|
||||
if (successOp == null)
|
||||
{
|
||||
foreach (var op in ops.Where(op => op.isDone))
|
||||
{
|
||||
Log.Net.Warning($"请求失败: {op.webRequest.url}, 错误: {op.webRequest.error}");
|
||||
}
|
||||
}
|
||||
@@ -240,32 +275,41 @@ namespace SGModule.Net {
|
||||
}
|
||||
|
||||
// 添加或删除检查 URL
|
||||
public void AddCheckUrl(string url) {
|
||||
if (!checkUrls.Contains(url)) {
|
||||
public void AddCheckUrl(string url)
|
||||
{
|
||||
if (!checkUrls.Contains(url))
|
||||
{
|
||||
checkUrls.Add(url);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveCheckUrl(string url) {
|
||||
if (checkUrls.Contains(url)) {
|
||||
public void RemoveCheckUrl(string url)
|
||||
{
|
||||
if (checkUrls.Contains(url))
|
||||
{
|
||||
checkUrls.Remove(url);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddPingTarget(string ip) {
|
||||
if (!_pingAddresses.Contains(ip)) {
|
||||
public void AddPingTarget(string ip)
|
||||
{
|
||||
if (!_pingAddresses.Contains(ip))
|
||||
{
|
||||
_pingAddresses.Add(ip);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemovePingTarget(string ip) {
|
||||
if (_pingAddresses.Contains(ip)) {
|
||||
public void RemovePingTarget(string ip)
|
||||
{
|
||||
if (_pingAddresses.Contains(ip))
|
||||
{
|
||||
_pingAddresses.Remove(ip);
|
||||
}
|
||||
}
|
||||
|
||||
// 切换是否使用 Ping 检测
|
||||
public void SetUsePingCheck(bool enablePing) {
|
||||
public void SetUsePingCheck(bool enablePing)
|
||||
{
|
||||
usePingCheck = enablePing;
|
||||
#if UNITY_WEBGL
|
||||
usePingCheck = false;
|
||||
@@ -273,8 +317,10 @@ usePingCheck = false;
|
||||
_checkInterval = usePingCheck ? PingInterval : WebRequestInterval;
|
||||
}
|
||||
|
||||
private bool QuickNetDeviceCheck() {
|
||||
if (Application.isEditor) {
|
||||
private bool QuickNetDeviceCheck()
|
||||
{
|
||||
if (Application.isEditor)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user