Android--socket 发送广播的那些坑

Socket广播包经常被用于局域网内的两台设备之间互相发现和消息传递,在Android应用开发过程中,也经常会遇到这样的需求,例如:两台Android设备之间、Android与手环等智能硬件之间、Android与Windows电脑之间等等。

本文主要介绍在Android中使用Socket开发广播包程序时需要注意的编程事项,以及解决方法。

首先给出一段Android发送广播包的示例代码:


1

2

3

4

5

6

7

8

DatagramSocket socket = new DatagramSocket(8000);

socket.setBroadcast(true);

InetAddress addr = InetAddress.getByName("255.255.255.255");

byte[] buffer = "Hello World".getBytes();

DatagramPacket packet = new DatagramPacket(buffer,buffer.length);

packet.setAddress(addr);

packet.setPort(8086);

socket.send(packet);

下面分析其中需要注意的地方:

1. 不要在主线程中发送广播包

当然,这个做Android开发的人应该都知道,不能在UI线程中执行任何网络访问相关的操作,由于广播包的发送也属于网络操作,因此必须放到单独的线程中执行。

2. 广播地址不建议使用“255.255.255.255”

上述代码中,广播包的目标地址设置为了“255.255.255.255”,其实,这并不是一种推荐的做法。

“255.255.255.255” 是一种受限的广播地址,常用于在计算机不知道自己IP地址的时候发送,比如设备启动时向DHCP服务器索要地址等等,一般情况下,路由器不会转发目标为受限广播地址的广播包。

而且,有些路由器/Wi-Fi热点不支持该广播地址(例如:用Android手机做Wi-Fi热点的时候),因此在程序中会出现“ENETUNREACH (Network is unreachable)”的异常,因此,为了保证程序成功发送广播包,建议使用直接广播地址,例如:当前IP地址是 192.168.1.100,子网掩码是 255.255.255.0 的情况下,广播地址为:192.168.1.255,(具体的推算方法这里就不展开了,可以参考计算机网络相关书籍)。

那么,如何得到本网段的直接广播地址呢,下面是stackoverflow上面有位大牛分享的代码:


1

2

3

4

5

6

7

8

9

10

11

12

public static InetAddress getBroadcastAddress(Context context) throws UnknownHostException {

    WifiManager wifi = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);

    DhcpInfo dhcp = wifi.getDhcpInfo();

    if(dhcp==null) {

        return InetAddress.getByName("255.255.255.255");

    }

    int broadcast = (dhcp.ipAddress & dhcp.netmask) | ~dhcp.netmask;

    byte[] quads = new byte[4];

    for (int k = 0; k < 4; k++)

        quads[k] = (byte) ((broadcast >> k * 8) & 0xFF);

    return InetAddress.getByAddress(quads);

}

直接使用该函数即可得到正确的“广播地址”,通过setAddress函数设置到DatagramPacket对象中即可。

3. Android设置为Wi-Fi热点时的广播地址

这是个比较大的坑,当Android设备被设置为Wi-Fi热点的时候,上面的函数得到的地址是"0.0.0.0",因此,我们需要探究当Android设备被设置为Wi-Fi热点的时候,它的IP地址究竟是多少?

有人研究了Android底层源码发现,当Android设备被设置为Wi-Fi热点的时候,其IP地址是hardcode写死在源码中的,地址是:“192.168.43.1”,对应的广播地址是:"192.168.43.255"

为此,我们需要写个函数来判断一下当前Android手机是否处于Wi-Fi热点模式下,如果是,则应该使用上面给出的这个广播地址,这里给出代码示例:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

protected static Boolean isWifiApEnabled(Context context) {

    try {

        WifiManager manager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);  

        Method method = manager.getClass().getMethod("isWifiApEnabled");

        return (Boolean)method.invoke(manager);

    }

    catch (NoSuchMethodException e) {

        e.printStackTrace();

    }

    catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)  {

        e.printStackTrace();

}

    return false;

}

Android SDK并没有开放判断是否处于热点模式的API,因此,我们需要通过反射的方式来得到,另外,注意添加权限:


1

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

4. 小结

本文涉及到的代码被封装到了一个Broadcaster.java的文件中,可以在博文最后的附件中下载,也可以从下面的地址下载:

https://github.com/Jhuster/Android/blob/master/Socket/Broadcaster.java

关于Android Socket发送广播包的那些坑就总结到这里了,有任何疑问或者建议欢迎留言或者来信[email protected]交流,或者关注我的新浪微博 @卢_俊获取最新的文章和资讯。

时间: 2024-12-14 18:11:53

Android--socket 发送广播的那些坑的相关文章

Android Socket 发送广播包的那些坑

Socket广播包经常被用于局域网内的两台设备之间互相发现和消息传递,在Android应用开发过程中,也经常会遇到这样的需求,例如:两台Android设备之间.Android与手环等智能硬件之间.Android与Windows电脑之间等等. 本文主要介绍在Android中使用Socket开发广播包程序时需要注意的编程事项,以及解决方法. 首先给出一段Android发送广播包的示例代码: DatagramSocket socket = new DatagramSocket(8000); socke

Android Socket发送信息时闪退

尝试Android写Socket通信的时候,遇到的个坑,记录一下: 1.无法建立连接. 原因:没有添加网络使用权限请求: 解决方式:在"AndroidMainfest.xml"中添加<uses-permission android:name="android.permission.INTERNET"/> 2.建立连接后正常接收信息,但发送信息时直接闪退,LogCat中异常提示为:android.os.NetworkOnMainThreadExceptio

Android Socket 发送与接收数据问题: 发送后的数据接收到总是粘包

先说明一下粘包的概念: 发送时是两个单独的包.两次发送,但接收时两个包连在一起被一次接收到.在以前 WinCE 下 Socket 编程,确实也要处理粘包的问题,没想到在 Android 下也遇到了.首先想从发送端能否避免这样的问题,例如: (1) 调用强制刷数据完成发送的函数:(2) 设置发送超时.1 先试了调用 flush() 函数,但运行后现象依旧2 设置发送超时是 Windows 平台的做法,但在 Android 平台下是否有类似的设置呢?查看 Socket 类的实现代码:java.net

Android笔记(二十六) Android中的广播——BroadcastReceiver

什么是广播? 为了方便进行系统级别的消息通知,Android有一套类似广播的消息机制,每个应用程序都可以对自己感兴趣的广播进行注册,这样该程序就只会接收自己所关心的广播内容,这些广播可能是来自于系统,也可能是来自于其他程序. 广播可以分为两种类型:有序广播和标准广播 标准广播是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因为它们之间没有任何先后顺序可言,这种广播的效率会比较高,但同时也意味着它是无法被截断的 如上图所示,每个人都代表一个广播接收器

Android socket 使用PrintWriter和BufferedReader发送和接收出现乱码问题解决

项目中用到了Android和C++的通信,选择了用socket 发送字符的方式,一开始使用的代码是: socket=new Socket(); InetSocketAddress isa = new InetSocketAddress(IP_STR, port); socket.connect(isa, 100); PrintWriter out=new PrintWriter(socket.getOutputStream(),true); BufferedReader recvBuf=new

android在广播接收器BroadcastReceiver里面再进行发送广播,造成当前广播接收器不断循环执行问题

最近在公司处理项目时,用到锁屏状态弹出activity进行提示,类似QQ消息弹屏提示的功能.当中用到了,假如该弹出activity已经位于锁屏界面外时,将不进行再次弹窗,而是发送广播进行通知数据更新,但是在广播接收器里面的某个步骤进行了再次发送通知的操作,发现该广播接收器变成了一个死循环的执行.经过仔细检查,发现没有任何一处用错action.  最终将该广播接收器里面的发送广播语句注释,死循环不在.代码如下: 注:里面的所有action都经过仔细检查,使用均正确,没任何错误,或者引用错误. pa

Android 两种注册、发送广播的区别

前言:前面文章记录了Service的使用,这次来记录另一个四个组件之一的BroadcastReceiver.主要介绍两种发送和注册广播的区别. BroadcastReceiver广播接收者用于接收系统或其他程序(包括自己程序)发送的广播. 一.注册广播 在android中,我们如果想接收到广播信息,必须自定义我们的广播接收者.要写一个类来继承BroadcastReceiver,并且重写其onReceive()方法,实现接收到特定广播所要做的事情. 这是一个自定义的广播接收者: public cl

Android 通过adb shell am broadcast发送广播

Android 通过adb shell am broadcast发送广播 adb shell am broadcast 后面的参数有: [-a <ACTION>][-d <DATA_URI>][-t <MIME_TYPE>] [-c <CATEGORY> [-c <CATEGORY>] ...] [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...] [--ez <EXTRA_K

Android应用程序发送广播(sendBroadcast)的过程分析

文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6744448 前面我们分析了Android应用程序注册广播接收器的过程,这个过程只完成了万里长征的第一步,接下来它还要等待 ActivityManagerService将广播分发过来.ActivityManagerService是如何得到广播并把它分发出去的呢?这就是 本文要介绍的广播发送过程了. 广播的发送过程比广播接收器的注册过程要复杂得多了