局域网主机广播寻找设备

源码及demo:UdpBroadcastSearcher

一、背景介绍

这是前面UDP网络编程中的实例(Android网络编程TCP、UDP(三)——UDP实例:搜索局域网所有的设备)。觉得这功能在以后可能会用上,就按照原思路优化了下代码。

主要优化的地方:

  • Android和Java工程中都可以使用
  • 用户可选择是否携带自定义协议数据。如设备(或主机)可以直接携带设备名称、房间等信息
  • 主机可把设备携带的信息可直接封装在设备对象中

二、原理回顾

主机与设备在同一局域网中,它们与路由器的连接为有线或无线。
这里写图片描述

实现原理:
这里写图片描述

这样就能获取到设备的IP地址,接下来就能随心所欲了,如建立TCP连接。

三、使用方法

3.1 不携带用户数据的使用(最简单的使用)

只要实现内部的抽象方法即可。

主机:

new SearcherHost() {
    @Override
    public void onSearchStart() {
        ...
    }

    @Override
    public void onSearchFinish(Set deviceSet) {
        //所有设备集合都在deviceSet中,通过getIp()可获取设备IP,getPort()获取端口
        ...
    }

    @Override
    public void printLog(String log) {
        ...
    }
}.search();

设备:

// 创建设备
SearcherDevice mSearcherDevice = new SearcherDevice() {
    @Override
    public void onDeviceSearched(InetSocketAddress inetSocketAddress) {
        // 主机IP: inetSocketAddress.getAddress().getHostAddress()
        // 主机端口:inetSocketAddress.getPort()
        ...
    }

    @Override
    public void printLog(String s) {
        ...
    }
};

// 打开设备
mSearcherDevice.open();

// 关闭设备
mSearcherDevice.close();

demo参考工程下的AppHost和AppDevice

3.2 携带用户数据的使用

若需要携带用户数据,必须重写类的用户数据打包与解包方法。

主机:

  1. 【可选】在构造方法中,指定泛型的具体类型。若不指定,parseUserData()也许需要强转。
  2. 在构造方法中,设置用于接收设备用户数据的最大字节长度(≥设备发送的用户数据长度)
  3. 在构造方法中,设置设备类的字节码,没有重写,则写SearcherHost.DeviceBean.class(用于内部通过反射创建实例对象)
  4. 重写两个用户数据打包方法:
    packUserData_Search()packUserData_Check()
  5. 重写用户数据解析方法:
    parseUserData(byte type, MyDevice device, byte[] userData)
SearcherHost searcherHost = new SearcherHost<MyDevice>(1024, MyDevice.class) {
    @Override
    public void onSearchStart() {
        ...
    }

    @Override
    public void onSearchFinish(Set deviceSet) {
        ...
    }

    @Override
    public void printLog(String log) {
        ...
    }

    /**
     * 重写以下3个方法
     */

    /**
     * 打包搜索时数据
     */
    @Override
    protected byte[] packUserData_Search() {
       ...
    }

    /**
     * 打包核对时的数据
     */
    @Override
    protected byte[] packUserData_Check() {
        ...
    }

    /**
     * 解析用户数据
     * @param type 类型。搜索申请or搜索确认
     * @param device 设备
     * @param userData 数据
     *
     * @return true-解析成功
     */
    @Override
    public boolean parseUserData(byte type, MyDevice device, byte[] userData) {
        ...
    }

};

// 开始搜索
searcherHost.search();

设备:

  1. 在构造方法中,设置用于接收设备用户数据的最大字节长度(≥主机发送的用户数据长度)
  2. 重写设备响应时的用户数据打包方法:
    packUserData()
  3. 重写用户数据解析方法:
    parseUserData(byte type, byte[] userData)
  4. 【可选】重写判断是否为本机ip地址的方法(主要用于判断主机确认返回的ip地址是否正确,默认返回true):
    isOwnIp(String ip)
SearcherDevice searcherDevice = new SearcherDevice(1024) {
    @Override
    public void onDeviceSearched(InetSocketAddress inetSocketAddress) {
        ...
    }

    @Override
    public void printLog(String s) {
        ...
    }


    /**
     * 重写以下2个方法
     */

    /**
     * 响应时的打包数据
     */
    @Override
    protected byte[] packUserData() {
        ...
    }

   /**
    * 解析用户数据
    * @param type 类型,搜索请求or搜索确认
    * @param userData 用户数据
    * @return 解析结果是否成功
    */
    @Override
    public boolean parseUserData(byte type, byte[] userData) {
        ...
    }

    /**
     * 判断ip是否是本机ip
     * @param ip 判断的ip地址
     * @return
     */
    @Override
    public boolean isOwnIp(String ip) {
        ...
    }
};

searcherDevice.open();

demo参考工程下的se_host和se_device。

demo中的se_host打印结果:
这里写图片描述

demo中的se_device打印结果:
这里写图片描述

利用jmdns发现局域网设备,在局域网内,你要通过一台主机和其他主机进行通信,你需要知道对方的ip地址,但是有些时候,你并不知道对方的ip地址,因为一般使用DHCP动态分配ip地址的局域网内,各个主机的IP地址是由DHCP服务器来帮你分配IP地址的。所以在很多情况下,你要知道对方的IP地址是比较麻烦的。 鉴于发现这篇文章最近的浏览量比较多,晚上也有不少转载,特别声明一下,文章水平可能不大够,只是我当时的一些理解,所以希望大家以批判的角度来看,然后又什么问题欢迎讨论。真心不希望误导大家^_^ mDNS就是来解决这个问题的。通过一个约定俗成的端口号,5353。(这个端口号应该是由IETF组织约定的。)每个进入局域网主机,如果开启了mDNS服务的话,都会向局域网内的所有主机组播一个消息,我是谁,和我的IP地址是多少。然后其他也有该服务的主机就会响应,也会告诉你,它是谁,它的IP地址是多少。当然,具体实现要比这个复杂点。 比如,A主机进入局域网,开启了mDNS服务,并向mDNS服务注册一下信息:我提供FTP服务,我的IP是192.168.1.101,端口是21。当B主机进入局域网,并向B主机的mDNS服务请求,我要找局域网内FTP服务器,B主机的mDNS就会去局域网内向其他的mDNS询问,并且最终告诉你,有一个IP地址为192.168.1.101,端口号是21的主机,也就是A主机提供FTP服务,所以B主机就知道了A主机的IP地址和端口号了。 大概的原理就是这样子,mDNS提供的服务要远远多于这个,当然服务多但并不复杂。 在Apple 的设备上(电脑,笔记本,iphone,ipad等设备)都提供了这个服务。很多Linux设备也提供这个服务。Windows的设备可能没有提供,但是如果安装了iTunes之类的软件的话,也提供了这个服务。 这样就可以利用这个服务开发一些局域网内的自动发现,然后提供一些局域网内交互的应用了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值