android如何判断两台设备在同一个局域网内

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tongsiw/article/details/89497809

android如何判断两台设备在同一个局域网内

判断两台设备在不在同一个局域网内有两种方法:

第一种方法是:分别拿到两台设备的ip地址(int类型的ip)和子网掩码(int类型的netMask),然后得到两台设备 ip and netMask 的值,如果相同就是在同一个局域网内,否则就不是。
第二种方法是:通过ping命令,得到TTL跳数,如果TTL跳数不是32,64,128,255之一,代表不是在同一个局域网。

第一种方法,比较(ip与netMask)的值

这种方法主要是根据ip地址(ip)和和子网掩码(netMask)判断的。首先查询ip和netMask,android端代码如下:

var wifiManager = context..getSystemService(Context.WIFI_SERVICE) as WifiManager
var dhcpInfo = wifiManager.getDhcpInfo();
var ipAddress = dhcpInfo.ipAddress;//ip地址,int类型的
var gateway = dhcpInfo.gateway;//网关地址,int类型的
var netmask = dhcpInfo.netmask;//子网掩码,int类型的

然后比较两个设备的  ipAddress and netmask  与运算的值是不是相等

需要权限

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

第二种方法,根据TTL跳数判定在不在同一个局域网

这个方法主要是通过ping命令,来得到TTL跳数,根据TTL跳数来判断。每台设备上TTL都有一个初始值,一般是32,64(常见),128,255(常见)。如果两台设备在同一个局域网,那么TTL就是32、64、128、255这4个数中的一个;
反之如果两台设备不在同一个局域网内,中间有路由器转发,那么
ping命令,相信大家都很熟悉,这里就不多说了。如果不懂的可以百度,网上有很多这方面的资料。直接上代码:

fun isInSameLAN(ipAddress: String): Boolean {
    var isInSameLAN = false
    try {
        val process = Runtime.getRuntime().exec("ping -c 1 -w 1 $ipAddress")
        var returnMsg = LineNumberReader(InputStreamReader(process.inputStream)).use {
            var sb = StringBuilder()
            var readLine: String?
            while (true) {
                readLine = it.readLine() ?: break
                sb.append(readLine)
            }
            sb.toString()
        }
        val splits = returnMsg.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
        for (i in splits.indices) {
            val split = splits[i]
            if (split.contains("ttl")) {
                if (split.contains("32") || split.contains("64") || split.contains("128") || split.contains("255")) {
                    isInSameLAN = true
                }
            }
        }
    } catch (e: IOException) {
        e.printStackTrace()
    }

    return isInSameLAN
 }

在这里插入图片描述
代买如下:

package jaydenxiao.com.sameintranet

import android.content.Context
import android.net.wifi.WifiManager
import java.io.IOException
import java.io.InputStreamReader
import java.io.LineNumberReader
import java.util.*


object SameLAN {
    fun getWifiManager(context: Context): WifiManager {
        return context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
    }

    /**
     * 获取IP地址。此方法获取的是转换后的ip地址
     * @param context
     * @return 转换后的IP地址: 类似 192.168.1.163
     */
    fun getIpAddress(context: Context): String {
        return toIP(getIpAddressInt(context))
    }

    /**
     * 获取IP地址。此方法获取的是没有转换的int类型的ip地址
     * @param context
     * @return 没有转换的ip地址:类似 -1560172352
     */
    fun getIpAddressInt(context: Context): Int {
        val dhcpInfo = getWifiManager(context).dhcpInfo
        return dhcpInfo.ipAddress
    }


    /**
     * 获取网关。转换后的网关
     * @param context
     * @return 转换后的网关:类似 192.168.1.1
     */
    fun getGateway(context: Context): String {
        return toIP(getGatewayInt(context))
    }

    /**
     * 获取网关。此方法获取的是没有转换的int类型的网关
     * @param context
     * @return 没有转换的网关:类似 16885952
     */
    fun getGatewayInt(context: Context): Int {
        val dhcpInfo = getWifiManager(context).dhcpInfo
        return dhcpInfo.gateway
    }

    /**
     * 获取子网掩码。获取的是转换后的子网掩码
     * @param context
     * @return 换后的子网掩码: 类似 255.255.255.0
     */
    fun getNetmask(context: Context): String {
        return toIP(getNetmaskInt(context))
    }

    /**
     * 获取子网掩码。此方法获取的是没有转换的int类型的子网掩码:16777215
     * @param context
     * @return 没有转换的子网掩码:类似16777215
     */
    fun getNetmaskInt(context: Context): Int {
        val dhcpInfo = getWifiManager(context).dhcpInfo
        return dhcpInfo.netmask
    }


    /**
     * 判断是不是在同一个局域网。
     * 原理是分别计算两部手机的 IP地址&子网掩码 的值,如果相等则表示在同一个局域网。
     * @param localAddress :本机的IP地址。这个IP地址是String类型的IP地址,详细请看{@link SameLAN#getIpAddress}
     * @param localMask :本机的子网掩码。这个子网掩码是String类型的子网掩码,详细请看{@link SameLAN#getNetmask}
     * @param otherAddress :另一部手机的IP地址。这个IP地址是String类型的IP地址,详细请看{@link SameLAN#getIpAddress}
     * @param otherMask :另一部手机的子网掩码。这个子网掩码是String类型的子网掩码,详细请看{@link SameLAN#getNetmask}
     * @return :{@code true : 表示在同一个局域网} {@code false : 表示不在同一个局域网}
     */
    fun isInSameLAN(localAddress : String, localMask: String, otherAddress: String, otherMask: String): Boolean {
        return isInSameLAN(toInt(localAddress),toInt(localMask),toInt(otherAddress),toInt(otherMask))
    }

    /**
     * 判断是不是在同一个局域网。
     * 原理是分别计算两部手机的 IP地址&子网掩码 的值,如果相等则表示在同一个局域网。
     * @param localAddress :本机的IP地址。这个IP地址是没有转换后的IP地址,详细请看{@link SameLAN#getIpAddressInt}
     * @param localMask :本机的子网掩码。这个子网掩码是没有转换后的子网掩码,详细请看{@link SameLAN#getNetmaskInt}
     * @param otherAddress :另一部手机的IP地址。这个IP地址是没有转换后的IP地址,详细请看{@link SameLAN#getIpAddressInt}
     * @param otherMask :另一部手机的子网掩码。这个子网掩码是没有转换后的子网掩码,详细请看{@link SameLAN#getNetmaskInt}
     * @return :{@code true : 表示在同一个局域网} {@code false : 表示不在同一个局域网}
     */
    fun isInSameLAN(localAddress: Int, localMask: Int, otherAddress: Int, otherMask: Int): Boolean {
        val local = localAddress and localMask
        val other = otherAddress and otherMask
        return local == other
    }

    /**
     * 判断是不是在同一个局域网。
     * 原理是根据TTL跳数来判断是不是在同一个局域网。他在设备B上有一个初始值,一般是32,64(常见),128,255(常见)。
     * 如果AB不能直达,中间有路由器转发,那么每过一个路由,TTL会减一,比如TTL在B的初始值是64,到A是62,说明中间被两个路由转发过。
     * 运用这个原理,当A去ping B的时候返回值如果不是32,64,128,255之一,而是略小于其中一个(比如62),那么说明A到B之间有路由器转发,即AB不在同一局域网内。
     * @param ipAddress :需要确定是不是在同一个局域网的另一个IP。可以是 "192.168.4.174",也可以是 "www.baidu.com"
     * @return {@code true : 表示在同一个局域网} {@code false : 表示不在同一个局域网}
     */
    fun isInSameLAN(ipAddress: String): Boolean {
        var isInSameLAN = false
        try {
            val process = Runtime.getRuntime().exec("ping -c 1 -w 1 $ipAddress")
            var returnMsg = LineNumberReader(InputStreamReader(process.inputStream)).use {
                var sb = StringBuilder()
                var readLine: String?
                while (true) {
                    readLine = it.readLine() ?: break
                    sb.append(readLine)
                }
                sb.toString()
            }
            val splits = returnMsg.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
            for (i in splits.indices) {
                val split = splits[i]
                if (split.contains("ttl")) {
                    if (split.contains("32") || split.contains("64") || split.contains("128") || split.contains("255")) {
                        isInSameLAN = true
                    }
                }
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }

        return isInSameLAN
    }

    /**
     * 将int类型的ip地址转换成String类型的
     * @param ip
     * @return
     */
    fun toIP(ip: Int): String {
        val sb = StringBuffer()
        sb.append(((ip and 0xff) as Int).toString())
        sb.append('.')
        sb.append(((ip shr 8 and 0xff) as Int).toString())
        sb.append('.')
        sb.append(((ip shr 16 and 0xff) as Int).toString())
        sb.append('.')
        sb.append(((ip shr 24 and 0xff) as Int).toString())
        return sb.toString()
    }

    /**
     * 将String类型的IP地址转换成int类型的IP地址
     * @param ip
     * @return
     */
    fun toInt(ip: String): Int {
        val token = StringTokenizer(ip, ".")
        var result: Int? = 0
        result = Integer.parseInt(token.nextToken()) shl 24
        result += Integer.parseInt(token.nextToken()) shl 16
        result += Integer.parseInt(token.nextToken()) shl 8
        result += Integer.parseInt(token.nextToken())
        return result!!
    }
}

全部源码

参考资料

猜你喜欢

转载自blog.csdn.net/tongsiw/article/details/89497809