【Android】TCP轮询扫描局域网设备

来源:互联网 发布:linux tar压缩目录 编辑:程序博客网 时间:2024/06/09 06:09

1.前言


  最近在做一个局域网通讯的项目,其通讯原理是扫描局域网内存在的设备,扫描完后后发送Socket验证消息到指定设备上,如果获取到返回消息,则表明扫描到目标设备,记录设备信息到设备列表,如果Socket连接超时,则不予记录。

2.TCP轮询扫描

  开启扫描时,先获取本机IP地址(如:192.168.1.105),然后使用ping命令轮询本网内可能存在的IP地址(192.168.1.1~192.168.1.255)。如果ping命令返回值正常,记录当前IP地址,当完成轮询任务后,开启设备验证任务,使用Socket发送验证消息到所有扫描成功的IP地址上(使用Socket.connect(SocketAddress remoteAddr, int timeout)来进行连接)用于获取设备信息,如果获取到返回值,则记录设备信息,如果出现连接超时,则不予记录。

3.TCP轮询的优缺点

1 优点

1.低丢包率:能够有效规避通讯丢包情况,避免扫描盲区;
2.扫描全面:在不考虑耗时的情况下,扫描结果还是比较全面的。

2 缺点

1.受网络状态影响:在网络状态不佳的情况下,容易遗漏设备(即双方通讯不通畅导致忽略);
2.耗时过长:如果为轮询设置连接超时(TimeOut)过长的话,会造成整个轮询过程的用时会比较长,不利于快速扫描;
3.负荷较大:如果采用多线程的方式来缩短整体扫描的时间,会增大当前应用负荷。

4.相关代码

package com.zihao.nw.test;import java.net.InetAddress;import java.net.NetworkInterface;import java.net.SocketException;import java.util.ArrayList;import java.util.Enumeration;import java.util.List;import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit;import org.apache.http.conn.util.InetAddressUtils;import android.text.TextUtils;import android.util.Log;/** * @ClassName:ScanDeviceTool * @Description:TODO<局域网扫描设备工具类> * @author:zihao * @date:2015年9月10日 下午3:36:40 * @version:v1.0 */public class ScanDeviceTool {    private static final String TAG = ScanDeviceTool.class.getSimpleName();    /** 核心池大小 **/    private static final int CORE_POOL_SIZE = 1;    /** 线程池最大线程数 **/    private static final int MAX_IMUM_POOL_SIZE = 255;    private String mDevAddress;// 本机IP地址-完整    private String mLocAddress;// 局域网IP地址头,如:192.168.1.    private Runtime mRun = Runtime.getRuntime();// 获取当前运行环境,来执行ping,相当于windows的cmd    private Process mProcess = null;// 进程    private String mPing = "ping -c 1 -w 3 ";// 其中 -c 1为发送的次数,-w 表示发送后等待响应的时间    private List<String> mIpList = new ArrayList<String>();// ping成功的IP地址    private ThreadPoolExecutor mExecutor;// 线程池对象    /**     * TODO<扫描局域网内ip,找到对应服务器>     *      * @return void     */    public void scan() {        mDevAddress = getLocAddress();// 获取本机IP地址        mLocAddress = getLocAddrIndex(mDevAddress);// 获取本地ip前缀        Log.d(TAG, "开始扫描设备,本机Ip为:" + mDevAddress);        if (TextUtils.isEmpty(mLocAddress)) {            Log.e(TAG, "扫描失败,请检查wifi网络");            return;        }        /**         * 1.核心池大小 2.线程池最大线程数 3.表示线程没有任务执行时最多保持多久时间会终止         * 4.参数keepAliveTime的时间单位,有7种取值,当前为毫秒         * 5.一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响         * ,一般来说,这里的阻塞队列有以下几种选择:         */        mExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_IMUM_POOL_SIZE,                2000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(                        CORE_POOL_SIZE));        // 新建线程池        for (int i = 1; i < 255; i++) {// 创建256个线程分别去ping            final int lastAddress = i;// 存放ip最后一位地址 1-255            Runnable run = new Runnable() {                @Override                public void run() {                    // TODO Auto-generated method stub                    String ping = ScanDeviceTool.this.mPing + mLocAddress                            + lastAddress;                    String currnetIp = mLocAddress + lastAddress;                    if (mDevAddress.equals(currnetIp)) // 如果与本机IP地址相同,跳过                        return;                    try {                        mProcess = mRun.exec(ping);                        int result = mProcess.waitFor();                        Log.d(TAG, "正在扫描的IP地址为:" + currnetIp + "返回值为:" + result);                        if (result == 0) {                            Log.d(TAG, "扫描成功,Ip地址为:" + currnetIp);                            mIpList.add(currnetIp);                        } else {                            // 扫描失败                            Log.d(TAG, "扫描失败");                        }                    } catch (Exception e) {                        Log.e(TAG, "扫描异常" + e.toString());                    } finally {                        if (mProcess != null)                            mProcess.destroy();                    }                }            };            mExecutor.execute(run);        }        mExecutor.shutdown();        while (true) {            try {                if (mExecutor.isTerminated()) {// 扫描结束,开始验证                    Log.d(TAG, "扫描结束,总共成功扫描到" + mIpList.size() + "个设备.");                    break;                }            } catch (Exception e) {                // TODO: handle exception            }            try {                Thread.sleep(1000);            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }    }    /**     * TODO<销毁正在执行的线程池>     *      * @return void     */    public void destory() {        if (mExecutor != null) {            mExecutor.shutdownNow();        }    }    /**     * TODO<获取本地ip地址>     *      * @return String     */    private String getLocAddress() {        String ipaddress = "";        try {            Enumeration<NetworkInterface> en = NetworkInterface                    .getNetworkInterfaces();            // 遍历所用的网络接口            while (en.hasMoreElements()) {                NetworkInterface networks = en.nextElement();                // 得到每一个网络接口绑定的所有ip                Enumeration<InetAddress> address = networks.getInetAddresses();                // 遍历每一个接口绑定的所有ip                while (address.hasMoreElements()) {                    InetAddress ip = address.nextElement();                    if (!ip.isLoopbackAddress()                            && InetAddressUtils.isIPv4Address(ip                                    .getHostAddress())) {                        ipaddress = ip.getHostAddress();                    }                }            }        } catch (SocketException e) {            Log.e("", "获取本地ip地址失败");            e.printStackTrace();        }        Log.i(TAG, "本机IP:" + ipaddress);        return ipaddress;    }    /**     * TODO<获取本机IP前缀>     *      * @param devAddress     *            // 本机IP地址     * @return String     */    private String getLocAddrIndex(String devAddress) {        if (!devAddress.equals("")) {            return devAddress.substring(0, devAddress.lastIndexOf(".") + 1);        }        return null;    }}
1 0