安卓基于MDNS协议的局域网内服务发现

mDNS简介

mdns 即多播(组播)dns(Multicast DNS),用于本地局域网服务发现的协议,在Apple 的设备上(电脑,笔记本,iphone,ipad等设备)都提供了这个服务(Bonjour)。

mDNS有以下几种免费实现方式:

avahi:Linux下实现(http://www.avahi.org/
jmDNS:JAVA实现(http://jmdns.sourceforge.net/
Bonjour:MAC OS实现(默认安装)
Bonjour:Windows下实现(https://support.apple.com/kb/DL999?locale=en_US

本文基于Jmdns开源库实现客户端服务端核心代码

客户端–》服务搜索

JmDNS方法都需要在子线程调用

获取本地IP InetAddress

 WifiManager wifiManager = (WifiManager) mContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
  private InetAddress getLocalIpAddress(WifiManager wifiManager) throws UnknownHostException {
        WifiInfo wifiInfo = wifiManager.getConnectionInfo();
        int intAddr = wifiInfo.getIpAddress();
        byte[] byteaddr = new byte[]{
                (byte) (intAddr & 255),
                (byte) (intAddr >> 8 & 255),
                (byte) (intAddr >> 16 & 255),
                (byte) (intAddr >> 24 & 255)};
        return InetAddress.getByAddress(byteaddr);
    }

初始化搜索监听

 private class JmdnsListener implements ServiceListener {
        private MdnsCallback mCallback;
        public JmdnsListener(MdnsCallback mCallback) {
            this.mCallback = mCallback;
        }
        public void serviceAdded(ServiceEvent ev) {
            Log.i(TAG, "serviceAdded: ");
            mJmdns.requestServiceInfo(ev.getType(), ev.getName(), 1);
        }
        public void serviceRemoved(ServiceEvent ev) {
            Log.i(TAG, "serviceRemoved: ");
            jsonMap.remove(ev.getName());
        }
        public void serviceResolved(ServiceEvent ev) {
            if (!jsonMap.containsKey(ev.getName())) {
                // 新设备
                JSONObject jsonObj = toJsonObject(ev.getInfo());
                Log.i(TAG, "serviceResolved: add");
                jsonMap.put(ev.getName(), jsonObj);
                if (mCallback != null) {
                    if (jsonObj == null) {
                        Log.w(TAG, "serviceResolved: jsonObj is null");
                        return;
                    }
                    // 重开线程回调
                    mCallback.onDeviceFind(jsonObj);
                }
            }
        }
    }

 /**
     * mDNS数据格式解析
     */
    private JSONObject toJsonObject(ServiceInfo sInfo) {
        JSONObject jsonObj;
        try {
            jsonObj = new JSONObject();
            String ipv4 = "";
            if (sInfo.getInet4Addresses().length > 0) {
                ipv4 = sInfo.getInet4Addresses()[0].getHostAddress();
            }

            // 发现的是被名称,ip 端口信息
            jsonObj.put("Name", sInfo.getName());
            jsonObj.put("IP", ipv4);
            jsonObj.put("Port", sInfo.getPort());

            byte[] allInfo = sInfo.getTextBytes();
            int allLen = allInfo.length;
            byte fLen;
            for (int index = 0; index < allLen; index += fLen) {
                fLen = allInfo[index++];
                byte[] fData = new byte[fLen];
                System.arraycopy(allInfo, index, fData, 0, fLen);

                String fInfo = new String(fData, StandardCharsets.UTF_8);
                if (fInfo.contains("=")) {
                    String[] temp = fInfo.split("=");
                    jsonObj.put(temp[0], temp[1]);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            jsonObj = null;
        }
        return jsonObj;
    }


加入组播并开始搜索服务


 private JmDNS mJmdns;
 private static final String mServiceName= "_sample._tcp.local.";// 要搜索的服务类型 类似_http._tcp.local.

 ServiceListener listener = new JmdnsListener(mCallback);
 InetAddress addr = getLocalIpAddress(wifiManager);
 mJmdns = JmDNS.create(addr);// step 1
 mJmdns.addServiceListener(mServiceName, listener); // step 2

结束搜索

 mJmdns.removeServiceListener(mServiceName, listener);
 mJmdns.close();

以上即为客户端搜索服务核心代码

服务端发布服务

注册服务


 private final static String REMOTE_TYPE = "_sample._tcp.local.";//注册服务类型,你的发现设备的代码中的type也是这个才能找到这个设备。

 // step 1 获取本地ip信息
 InetAddress ip = getLocalIpAddress(wifiManager);
 // step 2创建jmdns对象
 JmDNS jmdns = JmDNS.create(ip, "jmdnsSampleName");// jmdns实例名称
 // step 3发布的服务携带的额外参数
 final HashMap<String, String> values = new HashMap<String, String>();
 values.put("test", "vlaue");
 // step 4创建服务信息类,serverName唯一服务名称(发现端显示服务端的名字),PORT服务端提供建链的端口
 mServiceInfo = ServiceInfo.create(REMOTE_TYPE, serverName, PORT, 0, 0, values);
 // step 5 注册服务
 jmdns.registerService(mServiceInfo);

关闭服务:

  jmdns.unregisterService(mServiceInfo);
  jmdns.close();

搜索端抓包

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
设备发现:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值