mDNS即组播DNS(multicast DNS)。使用5353端口,在内网没有DNS服务器时,就会出现此组播信息。mDNS 基于 UDP 协议。.com/

在一个局域网内,每个进入局域网的主机,如果开启了mDNS服务的话,都会向局域网内的所有主机组播一个消息,告诉局域网内所有设备自己提供什么服务,服务名称,IP,端口等信息。比如A主机提供了某服务,A开启了mDNS,向局域网内广播发送mDNS消息:我的IP是 192.168.1.101,端口是9091。如果局域网中的B需要该服务,则 B 主机向局域网内广播 mDNS 服务请求,并且最终获得有一个IP地址为 192.168.1.100,端口号是 9091 的主机,也就是 A 主机提供 的服务 服务,所以 B 主机就知道了 A 主机的 IP 地址和端口号了。在我的第一篇文章中发送UDP数据包的IP和端口就是通过此方法获取的。

IPActivity.java:

package com.wifi.main;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


import javax.jmdns.JmDNS;
import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceInfo;
import javax.jmdns.ServiceListener;


import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.MulticastLock;
import android.os.Bundle;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;


import com.example.jushi_blub.R;
import com.wifi.connect.WIFIAdmin;
import com.wifi.mdns.Utils;
import com.wifi.utils.MyApplication;
import com.wifi.utils.WifiUtils;


public class IPActivity extends Activity implements OnClickListener{
public static final String TAG = "IPActivity";  
    private Button StartConnect,scan;
    //目的主机ip和端口
    private EditText IP,Port;
    //本机监听端口
    //private EditText LOCAL_PORT;
    private TextView destination,porttext;
    
    //目的ip和端口
    private String Server_IP;
    private String Server_Port;
    
    private Map<String, Object> map;
    private MyApplication myApplication;
    
    private WIFIAdmin wifiAdmin;
    private WifiManager mWifiManager;
    
    Handler handler = new Handler();
    
    //mdns服务类型
    private String type = "_udpserver._udp.local.";
//    private String type = "_sleep-proxy._udp.local.";
    private JmDNS jmdns = null;
    private ServiceListener listener = null;
    private ServiceInfo serviceInfo;
    
    //组播锁
    private MulticastLock lock;
    //展示扫描的mDNS服务
    private ListView mlistView;
    private Utils utils = new Utils();
    
  //存放扫描的mDNS服务
private List<Map<String, Object>> mdnsList= new ArrayList<Map<String,Object>>();
    private Map<String, Object> mdnsMap;
private boolean flag =true;
    
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ip);
        initViews();
        
        mlistView.setOnItemClickListener(new OnItemClickListener() {


@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position,
long id) {


AlertDialog.Builder alert = new AlertDialog.Builder(IPActivity.this);
Server_IP = mdnsList.get(position).get("Service_IP").toString();  
Server_Port = mdnsList.get(position).get("Service_Port").toString();  
            alert.setTitle(Server_IP);  
            alert.setMessage("点击获取");


            alert.setPositiveButton("获取", new DialogInterface.OnClickListener(){  
                @Override  
                public void onClick(DialogInterface dialog, int which) {  
                    IP.setText(Server_IP);
                    Port.setText(Server_Port);
                    
                }  
            });  
            alert.setNegativeButton("取消", new DialogInterface.OnClickListener(){  
                @Override  
                public void onClick(DialogInterface dialog, int which) {  
                    //  
                    //mWifiAdmin.removeWifi(mWifiAdmin.getNetworkId());  
                }  
            }); 
            alert.create();  
            alert.show();  
            
}
});
       
    }
    
    //开启查找服务
    private void setUp() {
    //打开组播 
        openBroadcast();
        
        try {
        //InetAddress ip = InetAddress.getByName("192.168.0.108");
        jmdns = JmDNS.create();
        //创建mDNS服务
        //serviceInfo = ServiceInfo.create(type, "AndroidTest",5353, "plain test service from android");
        //jmdns.registerService(serviceInfo);
            
            //监听mDNS服务
            jmdns.addServiceListener(type, listener = new ServiceListener() {

            @Override
                public void serviceResolved(ServiceEvent event) {
//            mdnsMap = new HashMap<String, Object>();
//
//            mdnsMap.put("Service_IP", ev.getInfo().getHostAddress());
//             mdnsMap.put("Service_Port", ev.getInfo().getPort());
//             if (!mdnsList.contains(mdnsMap)) {
//             mdnsList.add(mdnsMap);
//             }
            
            //ServiceInfo serviceInfo = jmdns.getServiceInfo(type, "light udpServer",1);
            
            String addr = "";
                if (event.getInfo().getHostAddress() != null && event.getInfo().getInetAddress()!=null) {
                        addr = event.getInfo().getHostAddress();
                    }
                mdnsMap = new HashMap<String, Object>();
                
                mdnsMap.put("Service_IP", addr);
                mdnsMap.put("Service_Port", event.getInfo().getPort());
                mdnsMap.put("service_Name", event.getName());
                
                if (!mdnsList.contains(mdnsMap)) {
                mdnsList.add(mdnsMap);
                }
                
                }


                @Override
                public void serviceRemoved(ServiceEvent ev) {
                 
                }


                @Override
                public void serviceAdded(ServiceEvent event) {
                    // Required to force serviceResolved to be called again (after the first search)
                    jmdns.requestServiceInfo(event.getType(), event.getName(), 1);
                }
});
            
        } catch (IOException e) {
            e.printStackTrace();
            return;
        } 
    }
    
 
    @Override
    protected void onStart() {
    super.onStart();

    }
    
    
    /**
     * 打开wifi组播服务
     */
    public void openBroadcast() {
    mWifiManager = (WifiManager) getSystemService(android.content.Context.WIFI_SERVICE);  
    if (!mWifiManager.isWifiEnabled()) {
    mWifiManager.setWifiEnabled(true);
}
    lock =mWifiManager.createMulticastLock(getClass().getSimpleName());  
    lock.setReferenceCounted(true);  
    lock.acquire();//to receive multicast packets  
    }
    

    /**
     * ListView的Item显示
     * @author Sunward
     *
     */
    public class MyAdapter extends BaseAdapter{
LayoutInflater inflater;
List<Map<String, Object>> list;

public MyAdapter(Context context, List<Map<String, Object>> list) {
this.inflater = LayoutInflater.from(context);
this.list = list;
}


@Override
public int getCount() {
return list.size();  
}


@Override
public Object getItem(int position) {
return list.get(position);  
}


@Override
public long getItemId(int position) {
return position;  
}


//忽略指定的警告
@SuppressLint({ "ViewHolder", "InflateParams" })  
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//针对每一个数据(即每一个List ID)创建一个ListView实例,
View view = null;
view = inflater.inflate(R.layout.wifi_listitem, null);
Map<String, Object> result = list.get(position);
TextView wifi_ssid=(TextView) view.findViewById(R.id.ssid);  
ImageView wifi_level=(ImageView) view.findViewById(R.id.wifi_level); 
wifi_ssid.setText(result.get("service_Name")+" "+result.get("Service_IP"));  
            wifi_level.setImageResource(R.drawable.wifi);  
            //判断信号强度,显示对应的指示图标    
             return view;  
}


}
    
    
    /**
     * 控件初始化
     */
    public void initViews(){
    //连接
    StartConnect = (Button) findViewById(R.id.startCon);
    //扫描
    scan = (Button) findViewById(R.id.scanService);
    IP = (EditText) findViewById(R.id.IPText); 
        Port = (EditText) findViewById(R.id.PortText);
        //LOCAL_PORT = (EditText) findViewById(R.id.LOCAL_PORT);
        
        destination = (TextView) findViewById(R.id.destination);
        porttext = (TextView) findViewById(R.id.porttext);
        
        //扫描的mdns服务
        mlistView=(ListView) findViewById(R.id.mdns_list); 
        
        StartConnect.setOnClickListener(IPActivity.this);
        scan.setOnClickListener(this);
        
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }


    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.wifi_config) {
        Intent intent = new Intent();
        intent.setClass(IPActivity.this, WIFIActivity.class);
        this.startActivity(intent);
        finish();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }


    /**
     * 返回键事件
     */
    @Override    
    public void onBackPressed() {    
        Intent intent = new Intent();
        intent.setClass(this, MainActivity.class);
        startActivity(intent);
        finish();
    } 
    
    /**
     * 按钮点击事件
     */
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.startCon:
myApplication = (MyApplication)this.getApplicationContext();
if (IP.getText().toString().trim().equals("")||
//LOCAL_PORT.getText().toString().trim().equals("")||
Port.getText().toString().trim().equals("")) {
Toast.makeText(IPActivity.this, "请输入完整", Toast.LENGTH_SHORT).show();  
}else {
Server_IP = IP.getText().toString();
Server_Port = Port.getText().toString();
Toast.makeText(IPActivity.this,Server_IP+"   "+Server_Port, Toast.LENGTH_SHORT).show();  
//Application存储全局变量
map = new HashMap<String, Object>();
map.put("IP", Server_IP);
map.put("Port", Server_Port);
map.put("LOCAL_PORT", 8929);

myApplication.setMap(map);
  
Intent intent = new Intent();  
intent.setClass(IPActivity.this,MainActivity.class);

startActivity(intent);  
finish();
}
break;

case R.id.scanService:
new Thread(){
        @Override  
           public void run()  
           {  
//         Looper.prepare();
setUp();
//加载扫描到的服务
//         Looper.loop();
           }  
        }.start();
        while(flag){  
        if (mdnsList.size()>0) {
        ListAdapter mAdapter = new MyAdapter(IPActivity.this, mdnsList);
        mlistView.setAdapter(mAdapter);  
        new WifiUtils.Utility().setListViewHeightBasedOnChildren(mlistView);  
        flag=false;
}
        
        } 
        break;
        default:  
            break;  
        }  


}

}

布局文件activity_ip.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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.wifi.main.IPActivity" >
 
    <ListView
    android:id="@+id/mdns_list"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/startCon"
     >
</ListView>


    <Button
        android:id="@+id/scanService"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:layout_below="@+id/IPText"
        android:layout_marginTop="80dp"
        android:layout_toRightOf="@+id/destination"
        android:text="扫描" />


    <TextView
        android:id="@+id/porttext"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:layout_below="@+id/destination"
        android:layout_alignLeft="@+id/mdns_list"
        android:text="站点端口" />


    <Button
        android:id="@+id/startCon"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/scanService"
        android:layout_alignBottom="@+id/scanService"
        android:layout_marginLeft="55dp"
        android:layout_toRightOf="@+id/scanService"
        android:text="连接" />


    <TextView
        android:id="@+id/destination"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/porttext"
        android:layout_alignParentTop="true"
        android:layout_marginTop="27dp"
        android:text="站点IP" />


    <EditText
        android:id="@+id/PortText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/porttext"
        android:layout_alignBottom="@+id/porttext"
        android:layout_alignLeft="@+id/IPText"
        android:layout_alignRight="@+id/mdns_list"
        android:ems="10"
        android:height="35dip"
        android:hint="Port"
        android:width="60dip" />


    <EditText
        android:id="@+id/IPText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/destination"
        android:layout_alignRight="@+id/mdns_list"
        android:layout_toRightOf="@+id/porttext"
        android:ems="10"
        android:hint="Please input IP"
        android:width="160dip" >


        <requestFocus />
    </EditText>


</RelativeLayout>


监听mDNS服务用的是jmDNS,大家可以去github下,里面也有教程,注意要下最新版本的,有的版本只能在Android5.1以下使用,很是头疼,当初我弄了好久也没找到问题所在。导入JmDNS的包,使用很简单,在上面的代码中,主要的部分是

jmdns.addServiceListener(type, listener = new ServiceListener() {

            @Override
                public void serviceResolved(ServiceEvent event) {

            String addr = "";
                if (event.getInfo().getHostAddress() != null && event.getInfo().getInetAddress()!=null) {
                        addr = event.getInfo().getHostAddress();
                    }
                mdnsMap = new HashMap<String, Object>();
                
                mdnsMap.put("Service_IP", addr);
                mdnsMap.put("Service_Port", event.getInfo().getPort());
                mdnsMap.put("service_Name", event.getName());
                
                if (!mdnsList.contains(mdnsMap)) {
                mdnsList.add(mdnsMap);
                }
                
                }
                @Override
                public void serviceRemoved(ServiceEvent ev) {
                 
                }
                @Override
                public void serviceAdded(ServiceEvent event) {
                    // Required to force serviceResolved to be called again (after the first search)
                    jmdns.requestServiceInfo(event.getType(), event.getName(), 1);
                }
});


            
serviceAdded(ServiceEvent event) 方法;监听服务调用的是serviceResolved(ServiceEvent event);当不想提供服务调用的是serviceRemoved(ServiceEvent ev) 方法。

效果图:

局域网扫描工具 Android 局域网扫描 安卓_ide