专栏首页程序猿的那点事Android开启热点后作为路由器,获取AP端IP地址

Android开启热点后作为路由器,获取AP端IP地址

最近在做类似面对面通信,需要一台手机作为AP端开启热点,另一台手机作为STA端连接热点,然后AP端告诉STA端它的IP地址,进行socket通信。 手机在联网时,就会被分配一个IP地址,它在开启热点时,它本身作为一个“路由器”也会生成一个IP地址,我们需要的就是后面这个IP地址,目前论坛上关于手机IP地址的帖子都是获取手机被分配的IP地址。我在解决这个问题时参考了蓝牙的配置IP地址,函数是configureBtIface(),在/frameworks/base/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java里。可以看到它也是先获取然后配置,参考这个,我写了获取热点IP地址的函数。

private String configureBtIface(boolean enable, String iface) {
        Log.i(TAG, "configureBtIface: " + iface + " enable: " + enable);

        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
        INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
        ConnectivityManager cm =
                (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        String[] bluetoothRegexs = cm.getTetherableBluetoothRegexs();

        InterfaceConfiguration ifcg = null;
        String address = null;
        try {
            ifcg = service.getInterfaceConfig(iface);
            if (ifcg != null) {
                InetAddress addr = null;
                LinkAddress linkAddr = ifcg.getLinkAddress();
                if (linkAddr == null || (addr = linkAddr.getAddress()) == null || addr.equals(
                        NetworkUtils.numericToInetAddress("0.0.0.0")) || addr.equals(
                        NetworkUtils.numericToInetAddress("::0"))) {
                    address = BLUETOOTH_IFACE_ADDR_START;
                    addr = NetworkUtils.numericToInetAddress(address);
                }

                ifcg.setLinkAddress(new LinkAddress(addr, BLUETOOTH_PREFIX_LENGTH));
                if (enable) {
                    ifcg.setInterfaceUp();
                } else {
                    ifcg.setInterfaceDown();
                }

                ifcg.clearFlag("running");
                service.setInterfaceConfig(iface, ifcg);

                if (enable) {
                    int tetherStatus = cm.tether(iface);
                    if (tetherStatus != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
                        Log.e(TAG, "Error tethering " + iface + " tetherStatus: " + tetherStatus);
                        return null;
                    }
                } else {
                    int untetherStatus = cm.untether(iface);
                    Log.i(TAG, "Untethered: " + iface + " untetherStatus: " + untetherStatus);
                }
            }
        }
        return address;
    }

下面getIpAddress()就是我写的开启热点以后获取AP端IP地址的函数,主要就是把蓝牙那边的参数改成了wlan0,就ok了。经过测试,log打出来的IP地址和手机执行ifconfig里wlan0里面的IP地址一模一样。当然,这个IP地址每次打开热点都是不一样的。在Android8.0以及之前这个IP地址是固定的,好像是"192.168.43.1"。9.0以后随机分配,可能是为了安全吧。

private String getIpAddress() {
        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
        INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
   
        InterfaceConfiguration ifcg = null;
        String address = null;
        try {
          ifcg = service.getInterfaceConfig("wlan0");
          if (ifcg != null) {
               LinkAddress linkAddr = ifcg.getLinkAddress();
               Log.d("test" , "linkAddr" + linkAddr.toString());
               if (linkAddr != null) {
                    InetAddress Inetaddr = linkAddr.getAddress();
                    Log.d("test" , "Inetaddr" + Inetaddr.toString());
                    if (Inetaddr != null) {
                         address = Inetaddr.getHostAddress();
                         if (address != null) {
                              Log.d("test" , "address " + address.toString());
                         }
                    }
               }
          }
        } catch (Exception e) {
            Log.e("test", "Error configuring interface :" + e);
            return null;
        }
        return address;
    }

这里贴上Android9.0上开启热点时分配IP地址(ipv4)的代码:/frameworks/base/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java里的configureIPv4()函数。

private boolean configureIPv4(boolean enabled) {
        if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")");

        // TODO: Replace this hard-coded information with dynamically selected
        // config passed down to us by a higher layer IP-coordinating element.
        String ipAsString = null;
        int prefixLen = 0;
        if (mInterfaceType == ConnectivityManager.TETHERING_USB) {
            ipAsString = USB_NEAR_IFACE_ADDR;
            prefixLen = USB_PREFIX_LENGTH;
        } else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
            ipAsString = getRandomWifiIPv4Address();
            prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH;
        } else {
            // Nothing to do, BT does this elsewhere.
            return true;
        }

        final LinkAddress linkAddr;
        try {
            final InterfaceConfiguration ifcg = mNMService.getInterfaceConfig(mIfaceName);
            if (ifcg == null) {
                mLog.e("Received null interface config");
                return false;
            }

            InetAddress addr = NetworkUtils.numericToInetAddress(ipAsString);
            linkAddr = new LinkAddress(addr, prefixLen);
            ifcg.setLinkAddress(linkAddr);
            if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
                // The WiFi stack has ownership of the interface up/down state.
                // It is unclear whether the Bluetooth or USB stacks will manage their own
                // state.
                ifcg.ignoreInterfaceUpDownStatus();
            } else {
                if (enabled) {
                    ifcg.setInterfaceUp();
                } else {
                    ifcg.setInterfaceDown();
                }
            }
            ifcg.clearFlag("running");
            mNMService.setInterfaceConfig(mIfaceName, ifcg);
        } catch (Exception e) {
            mLog.e("Error configuring interface " + e);
            return false;
        }

        // Directly-connected route.
        final RouteInfo route = new RouteInfo(linkAddr);
        if (enabled) {
            mLinkProperties.addLinkAddress(linkAddr);
            mLinkProperties.addRoute(route);
        } else {
            mLinkProperties.removeLinkAddress(linkAddr);
            mLinkProperties.removeRoute(route);
        }
        return true;
    }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Android GPS学习 (一) :GPS 启动流程

    packages/apps/Settings/src/com/android/settings/location/LocationSwitchBarContro...

    用户7557625
  • Android中Wifi网络配置信息的保存加载与更改—WifiConfigStore.java解析

    此类提供API以从持久性保存/加载/修改网络配置商店。 使用密钥库进行证书/密钥管理操作。 注意:此类只能在WifiConfigManager中使用,并且不是...

    用户7557625
  • WifiDisplay开启流程

    我们先来看一下WifiDisplay的代码,先从UI看起。 WifiDisplay是在Wifi P2P的基础上发展而来的,他的功能实现也离不开P2P。所以在W...

    用户7557625
  • 通过js判断访问设备是android还是IOS

    判断访问设备是android还是ios,无非就是获取设备的userAgent,下面来看一下通过正则表达式来判断访问设备是安卓还是苹果

    无邪Z
  • Android用webView包装WebAPP方法

    前一阵子,老板要将 WebAPP 放到 Android 和 iOS 里面,而我因为以前做过安卓,所以这方面就由我来打包,原理是很简单的,就是打开 APP 的时候...

    砸漏
  • Android使用MediaRecorder类实现视频和音频录制功能

    由官方配图可知,MediaRecorder用于录制视频时需要调用一系列的API来设置和录制相关的配置,而且调用方法的顺序是固定的,必须按照这个顺序进行API调用...

    砸漏
  • 洛谷 P1553 数字反转(升级版)【字符串+STL stack】

    P1553 数字反转(升级版) 题目描述 给定一个数,请将该数各个位上数字反转得到一个新数。 这次与NOIp2011普及组第一题不同的是:这个数可以是小数,分数...

    Angel_Kitty
  • Jupyter 工具的安装与使用方法,jupyter运行python代码演示,好用的python编辑器推荐!

    通过 jupyter notebook 启动环境,启用环境后这个窗口不要关闭。 快捷键 ctrl+c 可以停用服务。

    小蓝枣
  • 原生js判断操作系统和浏览器版本

    在诸如博客、论坛等系统的评论中,我们可以看见不少的网站都有显示发表评论的人的操作系统版本和浏览器版本。

    无道
  • Java StringTokenizer hasMoreElements()方法与示例

    StringTokenizer类的hasMoreElements()方法 (StringTokenizer Class hasMoreElements() me...

    用户7886150

扫码关注云+社区

领取腾讯云代金券