27 ตุลาคม 2555

[Android Code] การค้นหา IP ในวงแลนด้วย Ping


บทความนี้เป็นบทความที่เพิ่มเติมจากของเดิมนะ


จากบทความเดิมที่เจ้าของบล็อกได้บอกถึงข้อเสียของ ICMP
ว่าถ้าเครื่องไหนปิด Service ของ ICMP ไว้ ก็จะสแกนไม่เจอ
ดังนั้นบทความนี้ก็เป็นภาคต่อนั่นแหละ ว่าจะทำยังไงให้เจอทั้งหมด
ในบทความนี้ก็จะใช้อีกวิธีหนึ่งแทน เพื่อให้หาเจอทุกเครื่อง
โดยจะใช้วิธีที่โคตรคลาสสิคเลย ก็คือ การยิง Ping โดยตรงนั่นเอง
ซึ่งวิธีนี้จะใช้ได้กับทุกเครื่อง โดยจะให้ยิง Ping เพื่อตรวจสอบ
แทนการใช้ ECHO ของ ICMP จริงๆมันก็เหมือนกันนั่นแหละ

ดังนั้นคำสั่งในบทความนี้ก็จะไม่อธิบายอะไรมาก
จะอธิบายแค่ส่วนที่เปลี่ยนแปลงจากของเดิมเท่านั้น


IPDiscover.java
package app.akexorcist.ipviewerping;

import java.io.IOException;
import java.util.ArrayList;

import android.content.Context;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class IPDiscover {
    private Context mContext;
    private int count = 0;
    public boolean getIPState = false;
    public String DEVICE_IP_ADDRESS;
    private String ipTrim;
    private ArrayList<String> arr_ip;
    private ListView mListIP;
    private View mNormal, mLoad;
    
    public IPDiscover(Context context, ListView listIP, View normal
            , View load) {
        mContext = context;
        getDeviceIP();
        mListIP = listIP;
        mNormal = normal;
        mLoad = load;
    }
    
    public boolean isDiscovered() {
        return getIPState;
    }
    
    public String get(int index) {
        return arr_ip.get(index);
    }
    
    public ArrayList<String> getIPList() {
        return arr_ip;
    }
    
    private void getDeviceIP() {
        WifiManager wifiManager = 
                (WifiManager) mContext.getSystemService
                (Context.WIFI_SERVICE);
        WifiInfo wifiInfo = wifiManager.getConnectionInfo();
        int ipAddress = wifiInfo.getIpAddress();
        ipTrim = (ipAddress & 0xFF) + "."
                + ((ipAddress >> 8 ) & 0xFF) + "."
                + ((ipAddress >> 16 ) & 0xFF);
        DEVICE_IP_ADDRESS = (ipAddress & 0xFF) + "."
                + ((ipAddress >> 8 ) & 0xFF) + "."
                + ((ipAddress >> 16 ) & 0xFF) + "."
                + ((ipAddress >> 24 ) & 0xFF);
        Log.i("IP Discoverage",  "Device IP : " + DEVICE_IP_ADDRESS);
    }
    
    public void getConnectedDevices() {
        getIPState = false;
        Handler refresh = new Handler(Looper.getMainLooper());
        refresh.post(new Runnable() {
            public void run() {
                mNormal.setVisibility(View.INVISIBLE);
                mLoad.setVisibility(View.VISIBLE);
            }
        });
        
        arr_ip = new ArrayList<String>();
        setListView();
        
        for (int i = 0; i <= 255; i++) {
            final int j = i;
            Runnable runnable = new Runnable() {
                public void run() {
                    try {
                        Process proc = Runtime.getRuntime().exec
                                ("ping -c 3 " + ipTrim + "." 
                                + String.valueOf(j));
                        proc.waitFor();
                        int exit = proc.exitValue();
                        proc.destroy();
                        
                        if (exit == 0 && !(ipTrim + "." 
                                + String.valueOf(j)).equals
                                (DEVICE_IP_ADDRESS)) {
                            count++;
                            arr_ip.add(ipTrim + "." + String.valueOf(j));
                        } else {
                            count++;
                        }
                        
                        if(count >= 255) {
                            Handler refresh = 
                                    new Handler(Looper.getMainLooper());
                            refresh.post(new Runnable() {
                                public void run() {
                                    setListView();
                                    mNormal.setVisibility(View.VISIBLE);
                                    mLoad.setVisibility(View.INVISIBLE);
                                }
                            });
                            
                            getIPState = true;    
                            count = 0;
                        }
                    } catch (IOException e) {
                    } catch (InterruptedException e) { }
                }
            };
            new Thread(runnable).start();
        }
    }
    
    private void setListView() {
        mListIP.setAdapter(new ArrayAdapter<String>(mContext
                , android.R.layout.simple_list_item_1, arr_ip));        
    }
}

ส่วนที่เปลี่ยนแปลงก็จะอยู่ในลูป For เท่านั้น โดยจะเปลี่ยนจาก
ที่เดิมใช้ InetAddress ใช้เป็น Process ซึ่งเป็นคลาสที่เจ้าของบล็อก
เรียกมาเพื่อใช้คำสั่ง Ping นั่นเอง หรือก็ใช้วิธี Command Line นั่นเอง
โดยจะให้ Ping ไปที่ IP แล้วมีการเช็ค IP Address ชุดละ 3 รอบ
ถ้าไม่มีการ Ping กลับ หมายความว่า IP Address นั้นไม่มีเครื่องใดต่ออยู่
แต่ถ้ามีการตอบกลับก็จะให้เก็บ IP Adderss นั้นๆไว้ แต่สำหรับตัวอย่างนี้
จะเห็นว่าเจ้าของบล็อกได้สร้างตัวแปร count ขึ้นมา เพื่อใช้นับจำนวนครั้ง
เนื่องจากในคำสั่งนี้ทำงานบน Runnable ทั้งหมด เพื่อป้องกันแอพฯค้าง
ดังนั้นในลูป For จะวนเสร็จอย่างรวดเร็ว แต่การ Ping ยังรอการตอบกลับอยู่
ทำให้ยังไม่ได้ IP Address จนกว่าจะมีการตอบกลับหรือหยุดตรวจสอบ
จึงให้ตัวแปร count ทำการเพิ่มค่าทีละครั้งที่ตรวจสอบแต่ละ IP Address เสร็จ
โดย IP Address ที่ตรงกับตัวเองก็จะไม่เก็บค่าลง arr_ip
และเมื่อถึง 255 ก็หมายความว่าสแกนครบทุก IP Address แล้ว
จึงทำการดึง IP Address ที่สแกนเจอมาแสดงบน List View
เพียงเท่านี้ก็จะได้ IP Address ของทุกเครื่องในวงแลนแล้ว


Main.java
package app.akexorcist.ipviewerping;

import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ListView;
import android.widget.ProgressBar;

public class Main extends Activity {
    Button btnScan;
    ListView listIP;
    ProgressBar progressScan;
    IPDiscover ipd;
    
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        listIP = (ListView) findViewById(R.id.listIP);
        progressScan = (ProgressBar) findViewById(R.id.progressScan);
        progressScan.setVisibility(View.INVISIBLE);
        btnScan = (Button) findViewById(R.id.btnScan);
        btnScan.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                btnScan.setVisibility(View.INVISIBLE);
                ipd.getConnectedDevices();        
            }
        });
        
        ipd = new IPDiscover(this, listIP, btnScan, progressScan);
    }
}


สำหรับการใช้งานก็เหมือนกันเป๊ะๆ เพราะไม่ได้เปลี่ยนแปลงการแสดงผลเลย


main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <Button
        android:id="@+id/btnScan"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:text="SCAN" />
    <ProgressBar
        android:id="@+id/progressScan"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true" />
    <ListView
        android:id="@+id/listIP"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:layout_margin="40dp" />
</RelativeLayout>


AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="app.akexorcist.ipviewerping"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="15" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".Main"
            android:label="@string/title_activity_main" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>


สำหรับ AndroidManifest ไม่ต้องประกาศ User-Permission ของ INTERNET
เพราะไม่ได้ใช้แล้ว ใช้แต่ ACCESS_WIFI_STATE เพียงอย่างเดียว

สำหรับผู้ที่หลงเข้ามาอ่านคนใดต้องการดาวน์โหลดไฟล์ตัวอย่าง
สามารถดาวน์โหลดได้จากที่นี่เลย IPViewer-Ping [Google Drive]


เรียบร้อย~




เหล่าพันธมิตรแอนดรอยด์

Devahoy Layer Net NuuNeoI The Cheese Factory Somkiat CC Mart Routine Artit-K Arnondora Kamonway Try to be android developer Oatrice Benz Nest Studios Kotchaphan@Medium Jirawatee@Medium Travispea@Medium