安卓基于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();

搜索端抓包

在这里插入图片描述

在这里插入图片描述

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

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!要使用C语言编写一个在局域网内发布mDNS服务的程序,您可以使用开源的 mDNS 实现库,如 `Avahi` 或 `Bonjour`。这些库提供了API和功能,用于在局域网内发布和发现mDNS服务。 以下是一个使用 `Avahi` 库的示例程序,可用于在局域网内发布mDNS服务: ```c #include <stdio.h> #include <avahi-client/client.h> #include <avahi-client/publish.h> #include <avahi-common/simple-watch.h> #include <avahi-common/error.h> // 回调函数:当服务状态发生变化时调用 static void service_callback(AvahiClient *client, AvahiClientState state, void *userdata) { if (state == AVAHI_CLIENT_FAILURE) { fprintf(stderr, "服务注册失败:%s\n", avahi_strerror(avahi_client_errno(client))); avahi_simple_poll_quit(avahi_client_get_state(client)); } } int main() { int error; AvahiClient *client = NULL; AvahiEntryGroup *group = NULL; // 初始化mDNS客户端 client = avahi_client_new(avahi_simple_poll_get(), 0, service_callback, NULL, &error); if (!client) { fprintf(stderr, "无法创建mDNS客户端:%s\n", avahi_strerror(error)); return 1; } // 初始化服务组 group = avahi_entry_group_new(client, NULL, NULL); if (!group) { fprintf(stderr, "无法创建服务组:%s\n", avahi_strerror(avahi_client_errno(client))); return 1; } // 添加服务信息到服务组 error = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, "MyService", "_http._tcp", NULL, NULL, 1234, NULL); if (error != AVAHI_OK) { fprintf(stderr, "无法添加服务信息:%s\n", avahi_strerror(error)); return 1; } // 提交服务组中的服务信息 error = avahi_entry_group_commit(group); if (error != AVAHI_OK) { fprintf(stderr, "无法提交服务信息:%s\n", avahi_strerror(error)); return 1; } // 进入事件循环 avahi_simple_poll_loop(avahi_client_get_state(client)); // 清理资源 avahi_entry_group_free(group); avahi_client_free(client); return 0; } ``` 请注意,上述示例中使用的是 `Avahi` 库,因此您需要在编译时链接该库。编译命令如下: ```bash gcc -o mdns_service mdns_service.c -lavahi-client -lavahi-common ``` 这将生成一个可执行文件 `mdns_service`,运行该程序后,您的mDNS服务将在局域网内发布。 希望这能帮到您!如果您有更多问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值