Android-域名查询总结

作者: Jeremy_Ji | 来源:发表于2018-08-11 10:31 被阅读5次

这一段时间在给项目新增一个NsLookup功能并且学习了一些东西,已经有两周没有写博客了,正好有时间来做个总结。
先说一下这个功能:该功能是可以让用户输入一个域名然后显示它 的ip地址,并且在右上角菜单有可以查看历史记录的menu菜单,其中主要用到了一些知识例如网络请求,线程,以及dns等。实现效果和windows控制台输入nslookup+domain name效果差不多。

域名解析(功能主函数)

其中用到了该java类import org.xbill.DNS.*

 public String showDnsIp(String s)
            throws UnknownHostException, TextParseException {
        String ip=null;
//            String address = InetAddress.getByName(s).getHostAddress();
//            System.out.println(address);

        //查询类型为A类查询
        Lookup mlookup = new Lookup(s, Type.A);
        mlookup.run();
        //查询失败则返回错误信息
        if (mlookup.getResult() != Lookup.SUCCESSFUL) {
            System.out.println("ERROR: " + mlookup.getErrorString());
            ip = "Error:" + mlookup.getErrorString();
            return ip;
        }
        //获取结果
        Record[] answers = mlookup.getAnswers();
        for (Record rec : answers) {
            System.out.println(rec.toString());
            ip = rec.toString();

        }
        return ip;
    }

该java类对网络的请求以及实现过程可以看源码,而且可以注意到lookup函数中有一个type类型,那就是dns的查询类型。

nslookup有很多种查询种类如下:
A 地址记录
AAAA 地址记录
AFSDB Andrew文件系统数据库服务器记录
ATMA ATM地址记录
CNAME 别名记录
HINFO 硬件配置记录,包括CPU、操作系统信息
ISDN 域名对应的ISDN号码
MB 存放指定邮箱的服务器
MG 邮件组记录
MINFO 邮件组和邮箱的信息记录
MR 改名的邮箱记录
MX 邮件服务器记录
NS 名字服务器记录
PTR 反向记录
RP 负责人记录
RT 路由穿透记录
SRV TCP服务器信息记录
TXT 域名对应的文本信息
X25 域名对应的X.25地址记录

种类非常的多,但是最常用的还是A类查询

AsyncTask的使用

Android中对网络的请求需要把功能函数放到线程中去实现,从而不会导致整个主线程受到影响,可以选择用Android封装的线程类AsyncTask。AsyncTask是Android中的一个抽象类,需要去继承它然后使用,该类可以设置三个泛型参数
当我们子类继承一个AsyncTask时,至少要重写一个方法那就是(doInBackground(Params...)需要在线程中完成的事情,同类型参数而且可以传入多个)。通常也会实现这个方法(onPostExecute(Result)将结果返回给主线程,参数可以是doInBackground的返回值)。
这是官方给出的源码

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
             // Escape early if cancel() is called
             if (isCancelled()) break;
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
 }
 

一旦创建了任务需要在主线程中去调用

new DownloadFilesTask().execute(url1, url2, url3);

AsyncTask<URL, Integer, Long>这三个分别对应
1.Params----在主线程调用时传入的参数类型
2.Progress---由于在后台执行,该参数可以提供一个进度条或者等候界面(类似loading...)执行进度单元的类型,如果不需要则设为Void
3.Result---如果需要返回一个值给主线程可以设置参数形式

最终在界面实现方式可以是这样

   class MyNsTask extends AsyncTask<String, Void, String> {

        @Override
        protected String doInBackground(String... strings) {
            try {
                address = showDnsIp(mEdiText.getText().toString());
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (TextParseException e) {
                e.printStackTrace();
            }
            return address;
        }

        @Override
        protected void onPostExecute(String address) {
            super.onPostExecute(address);
            mTextView.setText(address);
        }


        /**
         * 查询时等待界面(可添加loading..)
         */
//    @Override
//    protected void onPreExecute() {
////            mTextView.setText("Wait while loading...");
//        super.onPreExecute();
//    }

}

调用函数并将结果显示在Textview中

   /**
         * 搜素按钮的点击事件
         * 点击时执行线程
         */
        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mEdiText.getText().toString().trim().equals("") ) {
                    mTextView.setText("Please enter domain name");
                } else {
//调用线程1
                    MyNsTask nsTask=new MyNsTask();
                    Log.d("--------"+mEdiText.getText().toString());
                    nsTask.execute(mEdiText.getText().toString());

                }

            }
        });

界面

ns--page.png

这个界面很简单,可以自己设计。

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/nslookup_layout"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:layout_marginTop="20dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <EditText
            android:id="@+id/edit_nslookup"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:hint="Enter domain name"
            android:lines="1"
            android:singleLine="true"
            android:layout_width="match_parent" />
        <Button
            android:id="@+id/btn_ns_clear"
            android:background="@drawable/ic_btn_clear"
            android:layout_width="25dp"
            android:layout_height="25dp"
            android:visibility="gone"/>

    </LinearLayout>
    <LinearLayout

        android:layout_marginTop="10dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <Button
            android:layout_marginBottom="10dp"
            android:layout_gravity="center"
            android:gravity="center"
            android:id="@+id/btn_nslookup"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:text="lookup" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:gravity="center_vertical"
            android:text="Search result:"
            android:textSize="20sp" />

        <TextView
            android:id="@+id/text_showip"
            android:layout_width="match_parent"
            android:layout_height="122dp"
            android:background="#5e2929"
            android:textIsSelectable="true"
            android:textSize="24sp" />


    </LinearLayout>

</LinearLayout>

设置可以查看搜索历史记录的menu

大致情况就是 查询时如果访问成功,则将域名用sharedpreferences存起来,利用一个符号比如逗号将每个域名连接起来拼成长字符串,之后在以逗号切割成一个个item放入dialog中。
实现的一个效果大概这样


ns--item1.png

点击右上角可以弹出菜单


ns--item2.png
点击按钮会弹出一个dialog显示搜索的记录(搜索失败,或者域名不对不会出现在历史记录)
nx--item3.png

活动中设置menu菜单

设置菜单比较简单就不多说了主要这三个方法

 /**
      *  创建菜单
      **/
    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.menu_nslookup_history,menu);
        super.onCreateOptionsMenu(menu, inflater);

    }

    @Override
    public void onPrepareOptionsMenu(Menu menu) {
        super.onPrepareOptionsMenu(menu);
    }

    /**
     * 设置菜单中的history按钮
     * @param item
     * @return
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        Log.i("NsLookupFragment onOptionsItemSelected");
        switch (item.getItemId()){
            case R.id.item_ns_history:
                //显示对话框
                showHistoryDialog();
                break;
                default:break;
        }
        return super.onOptionsItemSelected(item);
    }

设置item布局文件

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/item_ns_history"
        android:title="history"
        />
</menu>

点击菜单弹出对话框,点击clear可以清除历史记录

下面是dialog生成方式和实现history的方法放在了一起,主要用到的方法是setHistory()首先是生成dialog 的方法放在了上面onOptionsItemSelected(MenuItem item)的方法中
下面贴上代码

/**
     * 显示域名历史记录的dialog
     */
    public void showHistoryDialog(){
        mAllActivity=getActivity();
        AlertDialog.Builder mDialog=new AlertDialog.Builder(getActivity());
        /**
         * 设置列表内容(将从sp中取出的字符串以","分割成字符串数组)
         * 点击item时在输入框填入对应值
         * 点击clear时清空dialog
         */
        final String[] arrayOfString = this.getHistory().split(",");
        AlertDialog.Builder setItemsBuilder =
                mDialog.setItems(arrayOfString, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                setEditText(arrayOfString[which]);
            }
        });
        mDialog.setTitle("History").setPositiveButton
                ("Clear", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                setHistoryNull();
            }
        });
        mDialog.create();
        mDialog.show();
    }

保存历史到sharedpreferences中,因为要保存的数据也不会太多,所以没有使用数据库而是采用了轻量级的存储方案那就是sp,键值对,让数据对应history
首先是将搜到的域名以长字符串连接起来

private SharedPreferences mSharedPreferences;

 /**
     * 判断并将域名存入sp(以","为间隔将字符串拼接成长字符串)
     * @param domainName
     * @return
     */
    public void setHistory(String domainName) {
        SharedPreferences.Editor localEditor;
        String nsString = this.mSharedPreferences.getString("history", "");
        //判断字符串是否为空
        if (nsString==""){
            nsString = domainName;
            localEditor = this.mSharedPreferences.edit();
            localEditor.putString("history", nsString);
            localEditor.commit();
        }
        //判断字符串是否含有搜索过的的域名
        if (!nsString.contains(domainName)) {
            nsString = nsString + "," + domainName;
            localEditor = this.mSharedPreferences.edit();
            localEditor.putString("history", nsString);
            localEditor.commit();
        }
    }

该函数放在查询功能中加一个判断
放在之前的主函数中即可

  //查询成功则将域名传入sp
        if (mlookup.getResult()==Lookup.SUCCESSFUL){
            setHistory(s);
            Log.d("--------调试sp-------");
            System.out.print(mSharedPreferences.getString("history",""));
        }

之后是关于clear清空按钮的函数以及sp获取方法等

/**
     * 从sp中获取数据
     */
    public String getHistory()
    {
        return this.mSharedPreferences.getString("history", "");
    }


    /**
     * 清空dialog
     */
    public void setHistoryNull()
    {
        SharedPreferences.Editor localEditor = this.mSharedPreferences.edit();
        localEditor.putString("history", null);
        localEditor.commit();
    }


    /**
     * 设置输入框数据
     * @param paramString
     */
    public void setEditText(String paramString)
    {
        this.mEdiText.setText(paramString);
    }

做一个文本框清除按钮

ns--clear.png

思路也很清晰将按钮放在文本框末端并且设置成隐藏,与文本框的焦点获取绑定到一起即可

 android:visibility="gone"

那么之后在文件夹中添加一个图片类似于叉号的都可以
在drawable文件夹右键→new→image asset


imageassert.png imageassert1.png

google提供了很多Android原生按钮,样式背景以及颜色都可以自己实设置之后点击next然后添加到文件夹即可
然后实现代码

mClearButton=(Button) mNslookupView.findViewById(R.id.btn_ns_clear);
        mClearButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //点击按钮清空输入框
                mEdiText.getText().clear();
            }
        });
        mTextView = (TextView) mNslookupView.findViewById(R.id.text_showip);
        //输入框
        mEdiText = (EditText) mNslookupView.findViewById(R.id.edit_nslookup);
        //用户触摸EditText得到焦点
        mEdiText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (hasFocus){
                    //得到焦点时显示清除按钮
                    mClearButton.setVisibility(View.VISIBLE);
                }else {
                    //失去焦点时隐藏清除按钮
                    mClearButton.setVisibility(View.GONE);
                }
            }

        });

大概就完成了这么多,还可以添加一些东西例如回车键绑定搜索按键,对获取到的信息进行格式化处理,点击按钮直接copy显示出的ip点击并且直接访问该网站,最近在学习material design设计模式等等。
Android目前还在学习中在这里做点小总结,希望以后坚持下去,对工作或学习做一些总结,每天收获一点东西,厚积薄发。
最后贴上一张偶像照片。


王力宏《无问西东》饰演热血飞行员沈光耀.jpg

相关文章

  • Android-域名查询总结

    这一段时间在给项目新增一个NsLookup功能并且学习了一些东西,已经有两周没有写博客了,正好有时间来做个总结。先...

  • Android-域名查询总结2

    这次较上次的总结中新增了可以copy IP的功能,对文本框中现有的数据进行捕获并且进行处理(将查询信息中的格式解析...

  • nslookup

    命令作用 查询域名正向解析; 查询域名逆向解析; 查询域; 命令用法 直接查询 进入nslookup交互查询 常用...

  • 网站子域名的查询

    子域名查询

  • DAY1:域名、Whois查询、ICP备案查询

    关键词:域名、 whois 、ICP备案 重点:whois查询、ICP备案查询 1.域名介绍domain name...

  • gethostbyname与DNS

    一句话总结 域名查询(Domain Name Query)在Linux上的执行主要由glibc库函数gethost...

  • 渗透测试之信息收集

    1. 渗透测试之信息收集 1.1 收集域名信息 1.1.1 whois查询 还可以在以下网站查询域名的信息 1.1...

  • 准备面试题(从发送URL到收到结果经过了什么)

    1.DNS服务器对请求的域名进行解析,然后将会返回一个对应域名的可用ip----- 域名解析有两种查询,递归查询和...

  • 渗透测试常规流程

    1.信息收集 whois查询旁站,c段查询子域名查询 nmap-sP 192.168.1.100 ...

  • 域名信息查询

    你想知道网站域名的相关信息吗?其实很简单,跟谷哥或度娘说:whois,一大堆结果。在这里呢,就只给你推荐几个比较权...

网友评论

本文标题:Android-域名查询总结

本文链接:https://www.haomeiwen.com/subject/dpagvftx.html