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交流,或者关注我的新浪微博@卢_俊获取最新的文章和资讯。


本文出自 “对影成三人” 博客,请务必保留此出处http://ticktick.blog.51cto.com/823160/1707858

更多相关文章

  1. Android内核和驱动篇-Android内核介绍
  2. android总结之android初识
  3. Android(安卓)Socket 发送广播包的那些坑
  4. 深入解读Linux与Android的相互关系
  5. android CTS测试
  6. 将要更新到android 4.0的手机列表
  7. Android(安卓)音频简介(转)
  8. Android团队提供的示例项目
  9. 在android平台上如何实现H264解码

随机推荐

  1. 使用云服务器,如何实现Rdesktop连接?
  2. 【北亚数据恢复】DELL EqualLogic PS6100
  3. Web Components系列(三) —— 创建 Custom
  4. 云起实验室本周推荐体验场景,免费云上学习
  5. 怎么画人物的头发?插画人物头发绘画技巧!
  6. 软路由openwrt中替换国内镜像源(以阿里云
  7. 如何画好动漫的眼睛?动漫眼睛画法教程
  8. 【北亚数据恢复】HP P2000服务器 RAID5硬
  9. 初学者如何画好线条?练习画线条教学
  10. Eclipse阿里云镜像源配置