检查Unity中的互联网连接状态

17
我有一个Unity项目,我构建了Android和iOS平台。我想在桌面、Android和iOS设备上检查网络连接。我已经阅读过三种不同的解决方案:
  1. ping一些东西(例如Google)- 我完全不喜欢这样的决定,并且我已经阅读了有关Android错误的信息。
  2. Application.internetReachability - 根据Unity的文档,此函数仅确定我是否有可能连接到互联网(它不能保证真正连接)。
  3. Network.TestConnection() - 如果我没有互联网连接,则我的应用程序会失败。因此,这也不正确。
如何确定我在Unity中是否具有互联网连接?

5
Network.TestConnection() 为什么会导致应用程序失败?似乎加入一些错误处理就可以轻松解决。 - Ron Beyer
1
请使用ping的方法链接到提到的“错误”? - SimpleVar
2
如果 Network.TestConnection() 只在没有网络连接时抛出异常,那么只需将其包装在 try-catch 中。错误意味着没有网络连接,而没有错误则意味着您可以查看测试结果。 - SimpleVar
@RonBeyer 有很多主题都试图捕获这个异常,但我还没有看到任何准备好的答案。如果您能给我一个带有答案的链接,我会说“谢谢”。 - Anna Kuleva
3
这绝对不是链接问题的重复。这个问题是关于如何在PC、安卓和iOS上从Unity3D中使用C#检查连接性。提出的重复问题则是询问如何使用Objective-C从iOS SDK和Cocoa Touch检查连接性。这是两种完全不同的编程语言和技术栈。 - Maximillian Laumeister
显示剩余2条评论
9个回答

13

我实际上不认为Network.TestConnection()是适合这个任务的正确工具。根据文档,看起来它是用来测试NAT是否工作以及客户端是否可通过IP公开访问,但您想要检查的是是否具有一般互联网连接性。

这里是Unity Answers用户pixel_fiend提供的一个解决方案,只需测试一个网站以查看用户是否具有连接性。该代码的一个好处是它使用IEnumerator进行异步操作,因此连接性测试不会阻塞应用程序的其他部分:

IEnumerator checkInternetConnection(Action<bool> action){
     WWW www = new WWW("http://google.com");
     yield return www;
     if (www.error != null) {
         action (false);
     } else {
         action (true);
     }
 } 
 void Start(){
     StartCoroutine(checkInternetConnection((isConnected)=>{
         // handle connection status here
     }));
 }

您可以更改网站为任何您想要的内容,甚至可以修改代码以在可达到若干个站点中任意一个成功时返回。据我所知,没有办法在不尝试连接互联网上的特定站点的情况下检查真正的互联网连接性,因此通过类似这样的“ping”一个或多个网站可能是确定连接性的最佳选择。


如何调用 Action<bool> action?使用什么方法? - Haha TTpro
@HahaTTpro 使用 StartCoroutine(checkInternetConnection((isConnected)=>{/* 在这里处理连接状态 */})); - Maximillian Laumeister
谢谢您的回答,@Maximillian。但这不是我想要的。我的意思是“Action<bool>的命名空间是什么”,它是System.Action<bool>。 - Haha TTpro
@HahaTTpro 是的,没错,它是 System.Action。更多信息请参考:http://answers.unity3d.com/questions/335953/what-is-systemaction.html - Maximillian Laumeister
1
@AlirezaJamali WWW 继承自 CustomYieldInstruction,所以它确实支持 yield return。请参阅 Unity 文档中的 WWW,它在示例中使用了 yield return - Maximillian Laumeister
显示剩余4条评论

8
public static IEnumerator CheckInternetConnection(Action<bool> syncResult)
{
    const string echoServer = "http://google.com";

    bool result;
    using (var request = UnityWebRequest.Head(echoServer))
    {
        request.timeout = 5;
        yield return request.SendWebRequest();
        result = !request.isNetworkError && !request.isHttpError && request.responseCode == 200;
    }
    syncResult(result);
}

4
void Start()
{
    StartCoroutine(CheckInternetConnection(isConnected =>
    {
        if (isConnected)
        {
            Debug.Log("Internet Available!");
        }
        else
        {
            Debug.Log("Internet Not Available");
        }
    }));
}

IEnumerator CheckInternetConnection(Action<bool> action)
{
    UnityWebRequest request = new UnityWebRequest("http://google.com");
    yield return request.SendWebRequest();
    if (request.error != null) {
        Debug.Log ("Error");
        action (false);
    } else{
        Debug.Log ("Success");
        action (true);
    }
}

由于WWW已经被弃用,可以使用UnityWebRequest代替。


这个方法可能有效,但存在逻辑/成本问题。它加载整个页面来检查连接是否建立,因为它通过发送GET请求来实现,但在这种情况下(用于连接性检查),只发送Head请求就足够了(就像@KirillBelonogov的回答一样),因为我们不需要将页面加载或呈现给用户。 - undefined

2
不要发送GET请求,而是Ping 8.8.8.8。Unity已经提供了相应的工具:Ping。 ping操作是异步的,可以使用Ping.isDone来查询ping对象的状态。当收到响应时,它将显示在Ping.time中。
Windows Store Apps:使用流套接字模拟ping功能,它将尝试使用端口80打开到指定IP地址的连接。为了使其正常工作,必须在Package.appxmanifest中启用InternetClient权限。
Android:如果可用,ICMP套接字用于ping操作;否则,Unity将为ping操作生成子进程/system/bin/ping。若要检查是否存在ICMP套接字,请读取/proc/sys/net/ipv4/ping_group_range的内容。如果存在ICMP套接字,则该文件应包含0 2147483647的条目。
using UnityEngine;
using System.Collections.Generic;
 
public class PingExample : MonoBehaviour
{
    bool isConnected = false;
    private IEnumerator Start()
    {
        while(true)
        {
            var ping = new Ping("8.8.8.8");
 
            yield return new WaitForSeconds(1f);
            while (!ping.isDone) 
            {
                isConnected = false;
                yield return null;
            }
            isConnected = true;
            Debug.Log(ping.time);
        }
    }
}

请注意:在新的 Ping 请求后的前几帧中,ping.IsDone 的值为 false。 - Alireza Jamali
对于一个持续在线的游戏,while(ping.isDone)可能很有用,但这并不是获取设备连接状态的好方法。原因是"new Ping()"调用会阻止函数的剩余部分直到它被发送,并且只有在Internet可用时才会发送,这意味着循环将保持静止,永远不会告诉应用程序没有网络。 - user3345048
Unity Ping并不会停止函数的剩余部分,正如文档所述,它是异步的。关于“只有在网络可用时才会发送”,这正是关键所在,因为它无法发送,因此IsDone()返回false,这样你就知道没有网络连接。 - Alireza Jamali
你说的没错,但是你忘了一个关键点,设备可能无法知道它是否已经正确连接或者只是设置在网关上(比如公共WiFi需要登录才能使用)。在这种情况下,Pint()调用将被发送并且永远不会返回。你没有理解它的异步方面。调用它的函数如果Ping没有返回正确的值就不会继续执行。作为异步调用,这意味着其他脚本和update()方法将继续运行。 - user3345048
我认为你在说“调用它的函数不会继续”时并没有理解异步的含义,为什么你需要Ping使用的特定线程继续呢?它既不是主线程也不是UI线程,你的应用程序不会停止,因此它是一个异步方法/函数,你还可以手动设置超时时间,这样你就知道它需要多长时间才能返回。我自己使用多种方法,特别是你回答中提到的方法,但我首先使用Ping,其他方法作为备选方案。 - Alireza Jamali

1
我只是为了分享“ping”方法的经验而重新激活了这篇帖子: 几年前,我制作了一个(nodejs)软件包,它通过轮询一个简单的URL调用来检查连接性(默认URL = google.com),一切都正常运行。 直到有一天,一个用户下载了我的软件包,并向我反映了这个问题:他在他的公司的数百台计算机上使用我的软件包,每分钟都会多次访问默认的URL(默认为每秒一次!),这导致他的公司的IP被Google禁止访问,因为活动看起来可疑! 所以,根据使用环境,请谨慎使用这种方法!

1
我知道这已经过时了,但也许可以帮到您。
public bool CheckInternetConnection(){
    return !(Application.internetReachability == NetworkReachability.NotReachable)
}

它能在Android和iOS移动设备上运行吗? - Skylin R
1
是的,我进行了测试,这在所有设备和平台上都有效。 - kamiyar
1
你读了问题吗?它明确写着这是不够的。文档说这只是建议网络可用,并不意味着网络连接成功。例如,wifi 连接到一个路由器,但路由器没有外部连接。甚至有一个重复的点踩回答。 - user99999991
1
Application.internetReachability不适用于实际连接。 - Saad Anees
Application.internetReachability的结果不会取决于设备是否有访问互联网的权限(是否连接),而是取决于它是否具有访问互联网所需的组件。例如,如果您在PC上使用它,只要PC有网络适配器(现在已安装在主板上),它就会始终返回“通过本地区域网络可达”。如果智能手机上安装了SIM卡,则仅会返回“通过运营商数据网络可达”。即使设备离线,如果安装了SIM卡,它仍将返回“通过运营商数据可达”。 - user3345048

0

随着Unity的最新版本,WWW已经过时了,因此您需要使用WebRequest。

这是我正在使用的代码段,用于检查用户是否在线:

private string HtmlLookUpResult_Content;
private char[] HtmlLookUpResult_Chars;
private StreamReader HtmlLookUpResult_Reader;
private bool HtmlLookUpResult_isSuccess;
private HttpWebRequest HtmlLookUpResult_Request;
private HttpWebResponse HtmlLookUpResult_Response;
public bool CheckIfOnline()
{
    HtmlLookUpResult_Content = UniversalEnum.String_Empty;
    HtmlLookUpResult_Request = (HttpWebRequest)WebRequest.Create(UniversalEnum.WebHtml_isOnline);
    HtmlLookUpResult_Request.Timeout = 5000;
    try
    {
        using (HtmlLookUpResult_Response = (HttpWebResponse)HtmlLookUpResult_Request.GetResponse())
        {
            HtmlLookUpResult_isSuccess = (int)HtmlLookUpResult_Response.StatusCode < 299 && (int)HtmlLookUpResult_Response.StatusCode >= 200;
            if (HtmlLookUpResult_isSuccess)
            {
                using (HtmlLookUpResult_Reader = new StreamReader(HtmlLookUpResult_Response.GetResponseStream()))
                {
                    HtmlLookUpResult_Chars = new char[1];
                    HtmlLookUpResult_Reader.Read(HtmlLookUpResult_Chars, 0, 1);
                    HtmlLookUpResult_Content += HtmlLookUpResult_Chars[0];
                }
            }
        }
    }
    catch
    {
        HtmlLookUpResult_Content = UniversalEnum.String_Empty;
    }
    if (HtmlLookUpResult_Content != UniversalEnum.String_Empty)
    {
        return true;
    }
    else
    {
        return false;
    }
}

如果您想知道用户是否在线,您可以从代码中的布尔值HtmlLookUpResult_isSuccess获取结果。但是,实际上,您很可能还想确认用户是否也可以访问您在项目中使用的服务器或其他远程系统,对吧?这就是代码的其余部分所做的。

如果您想知道UniversalEnum是什么,在我的代码中,它是一个单独的非Monobehavior脚本,其中包含我计划在项目中重用的所有持久变量(如字符串和哈希)。简而言之:

UniversalEnum.String_Empty = "";

UniversalEnum.WebHtml_isOnline = "http://www.ENTER_YOUR_WEBSITE_HERE.com/games-latestnews/isOnline.html"

那个isOnline.html文件,正如你所看到的,是托管在我的网站HTML_content文件夹下的“games-latestnews”文件夹中的一个文件,它只包含[1]作为其内容。它没有标题,没有实际内容,基本上就像一个在线的.txt文件。我之所以使用这种方法,也是因为我可以通过在该文件夹中添加新的HTML页面来添加新闻到我的游戏中。我还用Try{}将内容检查包围起来,以便如果任何事情失败,它会返回Catch{}值,然后通过比较内容(一个字符串)是否为空字符串或包含任何内容,我们知道用户既在线又是否有访问您的网站的权限。

为什么要检查用户是否同时具有访问网络和访问您的网站的权限的一个很好的例子是,如果用户正在使用诸如学校之类的受限网络。如果学校由于任何原因决定禁止您的网站,仅仅查找连接是否可行将返回错误的结果,因为它无法访问实际的网页。


0

我创建了一个 Android 库,可以用作 Unity 插件。如果有人感兴趣,可以在 https://github.com/rixment/awu-plugin 下载。

至于 iOS 版本,很遗憾我在这个领域的知识不够。如果有人能扩展该存储库以包括 iOS 版本,那就太好了。


-2

您可以使用此代码检查网络连接

if(Application.internetReachability == NetworkReachability.NotReachable){
       Debug.Log("Error. Check internet connection!");
}

请查看以下链接以检查连接及其类型 -> https://docs.unity3d.com/ScriptReference/NetworkReachability.ReachableViaLocalAreaNetwork.html 然而,关于internetReachability:“不要使用此属性来确定实际的连接性。例如,设备可以连接到热点,但没有到达网络的实际路线。” https://docs.unity3d.com/ScriptReference/Application-internetReachability.html - Sergio Solorzano

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接