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


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


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


DatagramSocketsocket=newDatagramSocket(8000);socket.setBroadcast(true);InetAddressaddr=InetAddress.getByName("255.255.255.255");byte[]buffer="HelloWorld".getBytes();DatagramPacketpacket=newDatagramPacket(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上面有位大牛分享的代码:


publicstaticInetAddressgetBroadcastAddress(Contextcontext)throwsUnknownHostException{WifiManagerwifi=(WifiManager)context.getSystemService(Context.WIFI_SERVICE);DhcpInfodhcp=wifi.getDhcpInfo();if(dhcp==null){returnInetAddress.getByName("255.255.255.255");}intbroadcast=(dhcp.ipAddress&dhcp.netmask)|~dhcp.netmask;byte[]quads=newbyte[4];for(intk=0;k<4;k++)quads[k]=(byte)((broadcast>>k*8)&0xFF);returnInetAddress.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热点模式下,如果是,则应该使用上面给出的这个广播地址,这里给出代码示例:


protectedstaticBooleanisWifiApEnabled(Contextcontext){try{WifiManagermanager=(WifiManager)context.getSystemService(Context.WIFI_SERVICE);Methodmethod=manager.getClass().getMethod("isWifiApEnabled");return(Boolean)method.invoke(manager);}catch(NoSuchMethodExceptione){e.printStackTrace();}catch(IllegalAccessException|IllegalArgumentException|InvocationTargetExceptione){e.printStackTrace();}returnfalse;}


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


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


4. 小结


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


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


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



更多相关文章

  1. adb通过TCP/IP来调试Android设备
  2. Android获取设备ID号
  3. android sdk 下载地址
  4. Android(安卓)BroadcastReceiver 简介
  5. 【Android】Android(安卓)SDK在线更新镜像服务器
  6. android几种开源项目源码地址
  7. android sdk 下载地址
  8. 【Android】Android(安卓)Studio启动配置gradle
  9. 【Android(安卓)进阶】Android(安卓)Home 键监听

随机推荐

  1. 基于xml类型的压缩数据流的android获取天
  2. Android使用Http连接服务器,解析JSON, XML
  3. Android消息处理机制:Handler|Message
  4. Android分辨率
  5. Android(安卓)主题切换功能
  6. android中使用selector动态改变imageView
  7. Android 浏览器打开本地APK
  8. Android 自定义下拉列表
  9. Android记住用户
  10. Ice Cream Sandwich 为 Android 相机和相