Android 9 - 启用移动数据时套接字连接超时
Android 9 - Socket Connect TIMEOUT when Mobile data enabled
我有一个已部署的应用程序在 Android9 上失败。它的部分功能是通过接入点网络配置一个模块,以允许该模块连接到用户的家庭网络。
我有代码可以检测并连接到正确的 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()
是一个屏幕日志,因此在未连接到调试器时更容易看到发生了什么)。
知道出了什么问题吗?
在Android9中有一个关于网络的安全配置: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>
我不确定发生这种情况的确切原因。但是,当您打开移动数据并且仅使用移动数据连接到互联网时(考虑到您的 wifi 已关闭),它会从蜂窝网络获取 IP 地址,该网络不再连接到您的家庭网络。因此,预计这种超时情况是微不足道的,因为它无法到达以 192.168....
开头的家庭网络的私有 IP 地址。
现在我的困惑是,即使打开了移动数据,并且同时打开了 wifi 和移动数据,设备也应该默认连接到 wifi。
因此我建议您检查以下内容。
- Android 9 (Pie) 引入了特殊的 Wifi preference,它可以防止自动连接到 public 网络。您可以考虑检查设置。
- 请检查您设备的IP地址,是否有
192.168....
开头的IP地址。如果没有,那么肯定是您从蜂窝网络获取 IP 地址,因此它无法访问您家庭网络的私有 IP 地址。
经过几天的诅咒,我相信我已经找到了问题所在,因此找到了解决方案:
问题是由于 android 的版本发生了一些变化(我假设是 9.0,即使在 API 21 上发生了其他变化),特别是在创建套接字时,如果系统检测到有 "better" 网络(访问互联网、高信号等),套接字创建指的是该网络,而不是您想要的 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 一样工作的唯一方法。
我有一个已部署的应用程序在 Android9 上失败。它的部分功能是通过接入点网络配置一个模块,以允许该模块连接到用户的家庭网络。
我有代码可以检测并连接到正确的 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()
是一个屏幕日志,因此在未连接到调试器时更容易看到发生了什么)。
知道出了什么问题吗?
在Android9中有一个关于网络的安全配置: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>
我不确定发生这种情况的确切原因。但是,当您打开移动数据并且仅使用移动数据连接到互联网时(考虑到您的 wifi 已关闭),它会从蜂窝网络获取 IP 地址,该网络不再连接到您的家庭网络。因此,预计这种超时情况是微不足道的,因为它无法到达以 192.168....
开头的家庭网络的私有 IP 地址。
现在我的困惑是,即使打开了移动数据,并且同时打开了 wifi 和移动数据,设备也应该默认连接到 wifi。
因此我建议您检查以下内容。
- Android 9 (Pie) 引入了特殊的 Wifi preference,它可以防止自动连接到 public 网络。您可以考虑检查设置。
- 请检查您设备的IP地址,是否有
192.168....
开头的IP地址。如果没有,那么肯定是您从蜂窝网络获取 IP 地址,因此它无法访问您家庭网络的私有 IP 地址。
经过几天的诅咒,我相信我已经找到了问题所在,因此找到了解决方案:
问题是由于 android 的版本发生了一些变化(我假设是 9.0,即使在 API 21 上发生了其他变化),特别是在创建套接字时,如果系统检测到有 "better" 网络(访问互联网、高信号等),套接字创建指的是该网络,而不是您想要的 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 一样工作的唯一方法。