判断两台设备在不在同一个局域网内有两种方法:
第一种方法是:分别拿到两台设备的ip地址(int类型的ip)和子网掩码(int类型的netMask),然后得到两台设备 ip and netMask 的值,如果相同就是在同一个局域网内,否则就不是。
第二种方法是:通过ping命令,得到TTL跳数,如果TTL跳数不是32,64,128,255之一,代表不是在同一个局域网。
这种方法主要是根据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 与运算的值是不是相等
需要权限
这个方法主要是通过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!!
}
}
全部源码
参考资料