【问题标题】:Android 9 - Socket Connect TIMEOUT when Mobile data enabledAndroid 9 - 启用移动数据时的套接字连接超时
【发布时间】:2019-05-09 19:51:38
【问题描述】:

我有一个在 Android 9 上失败的已部署应用。它的部分功能是通过接入点网络配置一个模块,以允许该模块连接到用户的家庭网络。

我的代码可以检测并连接到正确的 WIFI 网络,但是当我尝试打开设备的套接字时,它会失败 - 仅在 Android 9 上且仅在启用移动数据的情况下。如果我手动禁用设备上的移动数据,一切正常。

Socket open() {
    Socket sock = new Socket(Proxy.NO_PROXY);
    try {
        sock.bind(new InetSocketAddress(localIpAddress(), 50000));
    } catch (IOException e) {
        activity.logContent("Warning: Failed to bind socket : " + e.toString());
    }
    try {
        sock.connect(new InetSocketAddress("192.168.17.1", 5555), (int)5000);
    } catch (IOException e) {
        // This catch fires when Mobile Data is on.
        activity.logContent("Connected to " + activity.mWifiManager.getConnectionInfo().getSSID());
        activity.logContent("Couldn't open socket : " + e.toString());
    }
    return sock;
}

我在有和没有Proxy.NO_PROXY 以及有和没有bind() 呼叫的情况下都试过这个。如果绑定调用丢失,则错误意味着套接字正在尝试通过蜂窝网络进行连接。 (注意:activity.logContent() 是屏幕日志,因此在未连接到调试器时更容易查看发生的情况。

有什么想法吗?

【问题讨论】:

标签: java android sockets android-wifi android-9.0-pie


【解决方案1】:

在 Android 9 中有一个关于网络的安全配置:Android security config

在 network_security_config 中添加您的域可能会解决您的问题。我的 network_security_config.xml 中有这个:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">119.xxx.xxx.xxx</domain>
    </domain-config>
</network-security-config>

【讨论】:

  • 感谢您的建议,我实际上已经有了该文件,但该项目是针对 19 构建的,因此我不确定是否正在使用权限文件。另外我(相信?)在这种情况下你会得到一个不同的错误(不是超时,而是一个安全错误),这并不能解释为什么当移动数据关闭时代码可以工作(从而强制套接字通过 Wifi 连接?)
【解决方案2】:

经过几天的咒骂,我相信我已经确定了问题并因此找到了解决方案:

问题的出现是由于 android 版本的一些变化(我假设是 9.0,即使 API 21 上发生了其他变化),特别是在创建套接字时,如果系统检测到存在“更好的”网络(访问互联网、高信号等)套接字创建是指该网络,而不是您想要的 wifi 网络。

我寻找在 wifi 网络(这是我想要的网络)上强制创建套接字的方法,我找到的唯一方法是:

简单地说,而不是:

Socket sock = new Socket();

做:

ConnectivityManager connectivity = (ConnectivityManager) MyApp.getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
                if (connectivity != null)
                {
                    for (Network network : connectivity.getAllNetworks())
                    {
                        NetworkInfo networkInfo = connectivity.getNetworkInfo(network);

                        if (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI)
                        {
                            if (networkInfo.isConnected())
                            {
                                Socket sock =  network.getSocketFactory().createSocket();
                            }
                        }
                    }
            }

实际浏览设备中存在的网络,当您找到您的活动 wifi 时,您什么也不做,只是利用此功能确保获得正确的套接字:

getSocketFactory().createSocket()

现在你有了工作套接字!

在我的情况下,它现在可以完美运行,如果有人找到更好的解决方案,这是受欢迎的,但目前这是我发现让一切都像以前版本的 android 一样工作的唯一方法。

【讨论】:

  • 我的客户已经确认这已经解决了他们的问题。谢谢。
【解决方案3】:

我不确定发生这种情况的确切原因。但是,当您打开移动数据并且仅使用移动数据连接到互联网时(考虑到您的 wifi 已关闭),它会从您的家庭网络中不再连接的蜂窝网络获取 IP 地址。因此,预计这种超时情况是微不足道的,因为它无法到达以192.168.... 开头的家庭网络的私有 IP 地址。

现在我的困惑是,即使打开了移动数据,并且同时打开了 wifi 和移动数据,设备应该连接到 wifi 作为默认行为。

因此,我建议您检查以下内容。

  • Android 9 (Pie) 引入了特殊的Wifi preference,可防止自动连接到公共网络。您可以考虑检查设置。
  • 请检查您的设备的IP地址,并检查它是否有一些以192.168....开头的IP地址。如果没有,那么肯定是您从蜂窝网络获取 IP 地址,因此它无法访问您的家庭网络的私有 IP 地址。

【讨论】:

  • 感谢您指出 WiFi 偏好。我们拥有的设备还包括为我们设置特定应用程序或不使用移动数据的能力。更改这些首选项不会产生任何影响。设备上的 localIpAddress() 调用解析为 192.168.17.2,这是设备接入点的 IP。
猜你喜欢
  • 2014-07-05
  • 2012-11-17
  • 2016-10-02
  • 1970-01-01
  • 1970-01-01
  • 2011-05-11
  • 1970-01-01
  • 2013-05-23
相关资源
最近更新 更多