This commit is contained in:
2026-06-12 17:14:59 +08:00
parent 84a14c06bd
commit b768474e67
51 changed files with 1011 additions and 391 deletions
@@ -7,24 +7,20 @@ 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
};
@@ -49,19 +45,16 @@ 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();
}
@@ -71,84 +64,69 @@ 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();
// }
@@ -156,13 +134,11 @@ 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;
}
@@ -175,46 +151,42 @@ 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 = true;
IsConnected = success;
}
/// <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;
@@ -230,30 +202,25 @@ 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;
}
@@ -262,10 +229,8 @@ 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}");
}
}
@@ -275,41 +240,32 @@ 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;
@@ -317,10 +273,8 @@ usePingCheck = false;
_checkInterval = usePingCheck ? PingInterval : WebRequestInterval;
}
private bool QuickNetDeviceCheck()
{
if (Application.isEditor)
{
private bool QuickNetDeviceCheck() {
if (Application.isEditor) {
return true;
}