现在大数据做的越来越变态,要求可以根据周边设备来完成。不讨论其他,就技术实现,其实很简单。
周边设备定义:同一路由下的周边设备,不局限android设备
实现原理:同一网段下,是根据Mac来通讯的。android设备上面,存储这ip和Mac一一对应的关系,是在arp表里面。
该信息存放在/proc/net/arp里面 。
实现步骤:1、解析/proc/net/arp文件,得到ip和Mac信息
2、考虑设备有可能没有和其他设备有通讯过,arp表没有缓存信息。
3、主动和同网段下,0-255的ip地址进行通讯,可以执行ping 命令或者发送udp包
4、重新读取/proc/net/arp
下面是一个demo,仅供参考。
demo兼容有线、wifi联网模式。
demo使用的是udp来更新arp信息。
demo内部处理网络是否连接的情况。
import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.DhcpInfo; import android.net.NetworkInfo; import android.net.wifi.ScanResult; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.Inet4Address; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import static CollectMacInterface.Collect_Mac_IO_ERROR; import static CollectMacInterface.Collect_Mac_Interrupt_ERROR; import static CollectMacInterface.IP_Format_ERROR; import static CollectMacInterface.Multiple_Call_ERROR; import static CollectMacInterface.Not_Connect_ERROR; import static CollectMacInterface.Not_IP_ERROR; import static CollectMacInterface.Not_Need_ERROR; import static CollectMacInterface.Not_Route_ERROR; public class CollectMacThread { private ExecutorService threadPool = null; private Context mContext = null; private boolean isCollectMac = false; private final static String TAG = "CollectMacThread"; private NetBroadcastReceiver receiver = null; private HashMap<String, String> ipAndMac = new HashMap<String, String>(); private String routeMac = ""; private volatile boolean hasInit = false; public CollectMacThread() { threadPool = Executors.newSingleThreadExecutor(); } public void start(Context context, boolean forceResearch, CollectMacInterface listener) { mContext = context; if (threadPool != null) { threadPool.shutdownNow(); threadPool = null; } threadPool = Executors.newSingleThreadExecutor(); this.isForceResearch = forceResearch; this.collectMacInterface = listener; threadPool.submit(new CollectRunnable(forceResearch, listener)); } private boolean isForceResearch = false; private CollectMacInterface collectMacInterface = null; private class CollectRunnable implements Runnable { private boolean force = false; private CollectMacInterface l; public CollectRunnable(boolean forceResearch, CollectMacInterface listener) { this.force = forceResearch; this.l = listener; } @Override public void run() { l.onStart(); if (force || !hasInit) { int res = collectMac(); if (res > 0) { hasInit = true; } } l.onFinish(res, ipAndMac, routeMac); } } public void stop() { unregister(); threadPool.shutdownNow(); threadPool = null; isCollectMac = false; } private void unregister() { if (mContext != null && receiver != null) { mContext.unregisterReceiver(receiver); receiver = null; } } int res = 0; // 获取本机ip,开启扫描;找到路由mac、本机mac;读取本机文件获取局域网mac;组装上传日志;确定后,退出app private int collectMac() { if (isCollectMac) { CollectMacLog.i(TAG, "collectMac(),do not need collect again isCollectMac===true"); res = Multiple_Call_ERROR; return res; } do { if (!isNeedCollectMac()) { CollectMacLog.i(TAG, "collectMac(),isNeedCollectMac==false,so do not collect mac"); res = Not_Need_ERROR; break; } if (!isConnected()) { CollectMacLog.i(TAG, "collectMac(),net not connect,so do not collect mac"); if (receiver == null) { receiver = new NetBroadcastReceiver(); mContext.registerReceiver(receiver, new IntentFilter( ConnectivityManager.CONNECTIVITY_ACTION)); } res = Not_Connect_ERROR; break; } String localIp = getLocalIp(); if (localIp == null || localIp.equals("")) { CollectMacLog.i(TAG, "collectMac(),local ip==null or '',so do not collect mac"); res = Not_IP_ERROR; break; } String regex = "(2[5][0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})"; if (!localIp.matches(regex)) { CollectMacLog .i(TAG, "collectMac(),local ip==" + localIp + ",so do not collect mac"); res = IP_Format_ERROR; break; } try { pingLocal(localIp.substring(0, localIp.lastIndexOf("."))); } catch (IOException e) { e.printStackTrace(); res = Not_Route_ERROR; break; } catch (InterruptedException e) { e.printStackTrace(); res = Collect_Mac_IO_ERROR; break; } if (!isConnected()) { CollectMacLog.i(TAG, "collectMac(),net not connect,so do not collect mac"); if (receiver == null) { receiver = new NetBroadcastReceiver(); mContext.registerReceiver(receiver, new IntentFilter( ConnectivityManager.CONNECTIVITY_ACTION)); } res = Not_Connect_ERROR; break; } boolean filter = filter(getMacs(), getRouteIp(localIp)); if (!filter) { CollectMacLog.i(TAG, "collectMac(),filter==" + filter + ",so do not collect mac"); res = Collect_Mac_Interrupt_ERROR; break; } isCollectMac = true; unregister(); res = 1; } while (false); CollectMacLog.i(TAG, "collectMac(),collect mac is ok?:" + isCollectMac); return res; } /** * 循环ping 局域网内的ip地址 * <p> * ping 太慢,改用arp 广播来实现。 * * @param preIp 表示ip前三位,如172.20.139 */ private void pingLocal(String preIp) throws IOException, InterruptedException { String target_ip = ""; for (int i = 0; i <= 255; i++) { target_ip = preIp + "." + i; if (i % 10 == 0) { CollectMacLog.i(TAG, "target ip == " + target_ip); } _ping(target_ip); } CollectMacLog.i(TAG, "ping finish"); } byte[] REQ = {(byte) 0x28, (byte) 0x73, (byte) 0x65, (byte) 0x6e, (byte) 0x64, (byte) 0x20, (byte) 0x62, (byte) 0x79, (byte) 0x20, (byte) 0x74, (byte) 0x29}; short UDP_PORT = 137; private void _ping(String target_ip) { if (target_ip == null || target_ip.equals("")) return; DatagramSocket socket = null; InetAddress address; DatagramPacket packet; try { address = InetAddress.getByName(target_ip); packet = new DatagramPacket(REQ, REQ.length, address, UDP_PORT); socket = new DatagramSocket(); socket.setSoTimeout(200); socket.send(packet); socket.close(); } catch (SocketException se) { } catch (UnknownHostException e) { } catch (IOException e) { } finally { if (socket != null) { socket.close(); } } } private boolean filter(HashMap<String, String> macs, String routeIp) { Iterator<Map.Entry<String, String>> iterator = macs.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<String, String> entry = iterator.next(); ipAndMac.put(entry.getKey(), entry.getValue().replaceAll(":", "")); CollectMacLog.i(TAG, " ip = " + entry.getKey() + ",mac ==" + entry.getValue()); } if (macs.containsKey(routeIp)) { routeMac = macs.get(routeIp).replaceAll(":", ""); } return true; } /** * 是否需要收集,控制是否要收集 */ private boolean isNeedCollectMac() { //待考虑的策略 return true; } private int getNetType() { ConnectivityManager connectivityManager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); if (networkInfo == null) { return -10; } return networkInfo.getType(); } private boolean isConnected() { ConnectivityManager connectivityManager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); if (networkInfo == null) { return false; } return networkInfo.isConnected(); } /** * 获取本机ip */ private String getLocalIp() { String localIp = ""; try { // 获取本地设备的所有网络接口 Enumeration<NetworkInterface> enumerationNi = NetworkInterface.getNetworkInterfaces(); while (enumerationNi.hasMoreElements()) { NetworkInterface networkInterface = enumerationNi.nextElement(); String interfaceName = networkInterface.getDisplayName(); String curType = (getNetType() == ConnectivityManager.TYPE_WIFI ? "wlan0" : "eth0"); CollectMacLog.i(TAG, "网络名字" + interfaceName); if (curType.equals(interfaceName)) { Enumeration<InetAddress> enumIpAddr = networkInterface .getInetAddresses(); while (enumIpAddr.hasMoreElements()) { // 返回枚举集合中的下一个IP地址信息 InetAddress inetAddress = enumIpAddr.nextElement(); // 不是回环地址,并且是ipv4的地址 if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) { CollectMacLog.i(TAG, inetAddress.getHostAddress() + " "); localIp = inetAddress.getHostAddress(); return localIp; } } } } } catch (SocketException e) { e.printStackTrace(); } return localIp; } /** * 获取路由Ip */ private String getRouteIp(String localIp) { String routeIp = ""; if (!isConnected()) { return routeIp; } routeIp = localIp.substring(0, localIp.lastIndexOf(".")) + ".1";//默认 if (getNetType() == ConnectivityManager.TYPE_WIFI) { WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); DhcpInfo info = wifiManager.getDhcpInfo(); if (info != null) { long mask = info.gateway; routeIp = long2ip(mask); return routeIp; } } //有线情况下,通过读取文件 File file = new File("/proc/net/route"); FileInputStream fileInputStream = null; InputStreamReader inputStreamReader = null; BufferedReader bufferedReader = null; try { fileInputStream = new FileInputStream(file); inputStreamReader = new InputStreamReader(fileInputStream); bufferedReader = new BufferedReader(inputStreamReader); String line = ""; int index = 0; HashMap<Integer, String> routes = new HashMap<Integer, String>(); while ((line = bufferedReader.readLine()) != null) { line = line.replaceAll("\\s{1,}", " "); routes.put(index, line); index++; } if (routes.size() > 2) { String routeIp16 = routes.get(1).split(" ")[2]; if (routeIp16.length() == 8) { StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append(Integer.parseInt(routeIp16.substring(6, 8), 16)); stringBuffer.append("."); stringBuffer.append(Integer.parseInt(routeIp16.substring(4, 6), 16)); stringBuffer.append("."); stringBuffer.append(Integer.parseInt(routeIp16.substring(2, 4), 16)); stringBuffer.append("."); stringBuffer.append(Integer.parseInt(routeIp16.substring(0, 2), 16)); routeIp = stringBuffer.toString(); } } } catch (Exception e1) { e1.printStackTrace(); } finally { try { if (bufferedReader != null) { bufferedReader.close(); bufferedReader = null; } if (inputStreamReader != null) { inputStreamReader.close(); inputStreamReader = null; } if (fileInputStream != null) { fileInputStream.close(); fileInputStream = null; } } catch (IOException e) { e.printStackTrace(); } } return routeIp; } String long2ip(long ip) { StringBuffer sb = new StringBuffer(); sb.append(String.valueOf((int) (ip & 0xff))); sb.append('.'); sb.append(String.valueOf((int) ((ip >> 8) & 0xff))); sb.append('.'); sb.append(String.valueOf((int) ((ip >> 16) & 0xff))); sb.append('.'); sb.append(String.valueOf((int) ((ip >> 24) & 0xff))); return sb.toString(); } /** * 获取mac */ public HashMap<String, String> getMacs() { HashMap<String, String> ipMacs = new HashMap<String, String>(); File file = new File("/proc/net/arp"); FileInputStream fileInputStream = null; InputStreamReader inputStreamReader = null; BufferedReader bufferedReader = null; try { fileInputStream = new FileInputStream(file); inputStreamReader = new InputStreamReader(fileInputStream); bufferedReader = new BufferedReader(inputStreamReader); String line = ""; while ((line = bufferedReader.readLine()) != null) { if (line.contains("IP")) { continue; } line = line.replaceAll("\\s{1,}", " "); String[] items = line.split(" "); if (!"00:00:00:00:00:00".equals(items[3])) { ipMacs.put(items[0], items[3]); } } } catch (FileNotFoundException e1) { e1.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } finally { try { if (bufferedReader != null) { bufferedReader.close(); bufferedReader = null; } if (inputStreamReader != null) { inputStreamReader.close(); inputStreamReader = null; } if (fileInputStream != null) { fileInputStream.close(); fileInputStream = null; } } catch (Exception e) { e.printStackTrace(); } } return ipMacs; } private class NetBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (isConnected()) { try { if (threadPool == null || threadPool.isShutdown()) { threadPool = Executors.newSingleThreadExecutor(); } threadPool.submit(new CollectRunnable(isForceResearch, collectMacInterface)); } catch (RejectedExecutionException e) { e.printStackTrace(); } } } } }
import java.util.HashMap; public interface CollectMacInterface { /** * 开始执行相关逻辑 */ void onStart(); /** * 执行完毕, resCode 表示结果,resCode>0,表示执行成功,resCode<0,表示各种异常 * routeMac 路由器的mac地址 * mac连接过路由的设备,列表里面包含本身的mac和路由器的mac。 * 格式是没有“:”的 */ void onFinish(int resCode, HashMap<String,String> mac, String routeMac); final static int Multiple_Call_ERROR = -1; final static int Not_Need_ERROR = -2; final static int Not_Install_ERROR = -3; final static int Not_Connect_ERROR = -4; final static int Not_IP_ERROR = -5; final static int IP_Format_ERROR = -6; final static int Not_Route_ERROR = -7; final static int Collect_Mac_IO_ERROR = -8; final static int Collect_Mac_Interrupt_ERROR = -9; }