鉴于此前博主发表过dlna开发的相关文章并在github上传了相关工程
github主页-->https://github.com/geniusgithub
亦有不少网友也下载使用了,其中不乏网友反馈说设备找不到或是搜索不稳定云云。。
这里可能原因有很多,下面就博主亲身经历简单阐述下几种可能的原因以及如何排查问题
1.路由环境问题(这种情况较少)
检测手段:下载bubbleupnp(一个很稳定的第三方客户端)
http://www.wandoujia.com/apps/com.bubblesoft.android.bubbleupnp
找两个手机安装下并接入路由器,如果搜索正常则排除此项
否则就是路由器问题,最简单的解决方法就是重启路由器
应该就可以了,如果始终不行就要检查下配置看看是不是设置了防火墙什么的(upnp组播禁用)
2.手机问题
很多手机平板类的移动设备上android系统默认是不打开组播锁的(应用接受组播消息会很耗电),所以需要额外在软件代码里额外加上打开关闭的操作
1)打开权限
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.INTERNET"/>
2.)打开组播锁
WifiManager wifiManager=(WifiManager)context.getSystemService(Context.WIFI_SERVICE);
MulticastLock multicastLock=wifiManager.createMulticastLock("MediaRender");
if (multicastLock != null){
multicastLock.acquire();
}
3)关闭组播锁
在退出软件的时候记得关闭
if (mMulticastLock != null){
mMulticastLock.release();
mMulticastLock = null;
}
很多不稳定的原因都是因此造成的,在有些设备上甚至会影响到udp单播的接收
对于dmr,dms如果无法接收组播消息则意味着无法响应客户端的searh消息
对于dmp,dmc如果无法接收组播则得不得dmr,dms的上线下线消息,如果连udp单播接收都有问题,那么发出去的search消息即便对方有回应也接收不到,这些都会造成设备找不到或是搜索不稳定的问题
(当然同一个设备上的两个应用之间通讯不存在上述问题)
3.丢包问题
不论是udp组播还是udp单播,在路由器传输过程中都有可能丢包,所以为了尽量避免这种情况,可以在进行组播通知或是搜索的时候多发几次包(比如三次)
当然也不宜过多,否则会造成网络拥塞影响性能,这也引申出另一个问题,若是在网络环境较为复杂的路由器下测试dlna性能是很不理想的(丢包严重)
4.人品问题
简单来说就是丫的两个设备明明没在一个局域网,还嚷嚷着为什么设备找不到
尤其是设备在使用wifi接入条件下,如果wifi不稳定断开了,很可能就连上另一个wifi网了,再说博主的代码有问题LZ就要骂人了
基本上第二点是需要大家注意的,不论是服务端应用还是客户端应用
早些时候可能因为没加上组播锁的缘故,所以会有类似问题,不过写这篇文章的时候
相关code已经commit修改了,请大家下载更新
在反编译了诸如搜狐视频,网易视频等APK发现它们并未添加组播锁,作为dmc就可能导致无法收到dmr的notify组播消息,只能依赖search机制,正如前面所说,部分手机甚至连udp单播都会受影响,那么搜索不到设备也就不奇怪了。
这时候又想使用这些软件怎么办?刚刚给大家推荐了一款软件bubbleupnp,它有一种神奇的魔力,可以打开系统组播锁,让其他应用也能正常接收到组播(LZ至今尚不明白它是怎么做到的,有知道的麻烦告知)
另外附上一个用于组播测试的demo
下载地址:http://download.csdn.net/detail/geniuseoe2012/6847963
截图:
代码片段
public class MulSocketMng {public static interface RecDataCallback{public void onDataReceive(String hostIP, int port, final String data);}private static final CommonLog log = LogFactory.createLog();private final static int RECDATA_MSG_ID = 0x0001;private MulticastSocket multicastSocket; private InetAddress mGroup;private int mLocalPort;private boolean isInit = false;private HandlerThread mHandlerThread;private Handler mRecHandler;private RecDataCallback mCallback;public MulSocketMng(){}public boolean openSokcet(String groupIP, int localPort){if (isInit){return true;}try {mLocalPort = localPort;multicastSocket = new MulticastSocket(mLocalPort);multicastSocket.setLoopbackMode(true);mGroup = InetAddress.getByName(groupIP);multicastSocket.joinGroup(mGroup);isInit = true;} catch (Exception e) {e.printStackTrace();}return isInit;}public void closeSocket(){if (!isInit){return ;}try {multicastSocket.leaveGroup(mGroup);multicastSocket.close();} catch (Exception e) {e.printStackTrace();}stopListenThead();isInit = false;}public boolean syncSendData(String data, String targetIP, int targetPort){if (!isInit){return false;}SendTask task = new SendTask(data, targetIP, targetPort);Thread thread = new Thread(task);thread.start();return true;}public boolean startListenThread(RecDataCallback callback){if (!isInit){return false;}if (mHandlerThread == null){startRevThread();mRecHandler.sendEmptyMessage(RECDATA_MSG_ID); mCallback = callback;}return true;}public void stopListenThead(){closeRecThread();}private class SendTask implements Runnable{private String mData;private String mTargetIP;private int mTargetPort;public SendTask(String data, String targetIP, int targetPort){mData = data;mTargetIP = targetIP;mTargetPort = targetPort;}@Overridepublic void run() {try {byte []data = mData.getBytes("utf-8");InetAddress targetAddress = InetAddress.getByName(mTargetIP);DatagramPacket outPacket = new DatagramPacket(data, data.length, targetAddress, mTargetPort);MulticastSocket socket = new MulticastSocket();log.e("syncSendData mTargetIP = " + mTargetIP + ", TARGET_PORT = " + mTargetPort + "\ncontent --> " + mData);socket.send(outPacket); socket.close();} catch (Exception e) {e.printStackTrace();}}private void sendUDP(String data, String ip, int port) {try {byte[] datas = data.getBytes("utf-8");InetAddress targetAddress = InetAddress.getByName(ip);DatagramPacket packet = new DatagramPacket(datas, datas.length, targetAddress, port);} catch (Exception e) {e.printStackTrace();} }}private boolean startRevThread(){if (mHandlerThread != null){return true;}mHandlerThread = new HandlerThread(""); mHandlerThread.start();mRecHandler = new Handler(mHandlerThread.getLooper()){@Overridepublic void handleMessage(Message msg) {switch(msg.what){case RECDATA_MSG_ID:try {while(true){revData();} } catch (IOException e) {e.printStackTrace();}break;}}};return true;}private void closeRecThread(){if (mHandlerThread == null){return ;}mHandlerThread.quit();mHandlerThread = null;}private boolean revData() throws IOException { byte[] receiveData = new byte[1024]; DatagramPacket packet = new DatagramPacket(receiveData, receiveData.length); log.e("block to receive packet!!!groupIp = " + mGroup.getHostAddress() + ", port = " + mLocalPort); multicastSocket.receive(packet); String packetIpAddress = packet.getAddress().toString();packetIpAddress = packetIpAddress.substring(1, packetIpAddress.length()); log.e("rec packet from --> ip: " + packetIpAddress + ", port = " + packet.getPort());String content = new String(receiveData, "utf-8");content = content.trim();log.e("content --> " + content); if (mCallback != null){mCallback.onDataReceive(packetIpAddress, packet.getPort(), content);}return true;}
}
public class MainActivity extends Activity implements OnClickListener,MulSocketMng.RecDataCallback,OnCheckedChangeListener{private static final CommonLog log = LogFactory.createLog();private static final String GROUP_IP = "239.255.255.250";private TextView mTextView;private Button mButtonSend;private Button mButtonOpen;private Button mButtonClose;private Button mButtonClear;private TextView mTVContent;private ScrollView mScrollView;private RadioGroup mRadioGroup;private MulSocketMng mSocketMng;private MulticastLock mMulticastLock;private StringBuffer mDataBuffer = new StringBuffer();private UnickSocketMng mUnickSocketMng;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);setupViews();initData();}@Overrideprotected void onDestroy() {closeWifiBrocast();super.onDestroy();}private void setupViews(){mTextView = (TextView) findViewById(R.id.textview);mButtonSend = (Button) findViewById(R.id.btnSend);mButtonOpen = (Button) findViewById(R.id.btnOpen);mButtonClose = (Button) findViewById(R.id.btnClose);mButtonClear = (Button) findViewById(R.id.btnClear);mButtonClose.setOnClickListener(this);mButtonOpen.setOnClickListener(this);mButtonSend.setOnClickListener(this);mButtonClear.setOnClickListener(this);mTVContent = (TextView) findViewById(R.id.tv_content);mScrollView = (ScrollView) findViewById(R.id.sv_view);mRadioGroup = (RadioGroup) findViewById(R.id.rg_group);mRadioGroup.setOnCheckedChangeListener(this);}private void initData(){ mSocketMng = new MulSocketMng();mUnickSocketMng = new UnickSocketMng();}private void updateText(String groupIP, int port){StringBuffer sBuffer = new StringBuffer();sBuffer.append("Socket Bind --> groupIP = " + groupIP + ", port = " + port);mTextView.setText(sBuffer.toString());}private void clearText(){mTextView.setText("socket close...");clearContent();}private void updateContent(String hostIP, int port, final String data){mDataBuffer.append("rec from ip:" + hostIP + ", port = " + port);mDataBuffer.append("\n" + data + "\n-----------------\n");mTVContent.setText(mDataBuffer.toString());mScrollView.scrollTo(0, 1024 * 1024);}private void clearContent(){mDataBuffer = new StringBuffer();mTVContent.setText("");}@Overridepublic void onClick(View v) {switch(v.getId()){case R.id.btnClose:close();break;case R.id.btnOpen:open();break;case R.id.btnSend:send();break;case R.id.btnClear:clearContent();break;}}private static final int TARGET_PORT = 1900;private void send(){String value = "test mulbrocast!!!";boolean ret = mSocketMng.syncSendData(value, GROUP_IP, TARGET_PORT);mUnickSocketMng.syncSendData("udpdata..", "192.168.11.3", 12345);}private static final int LOCAL_PORT = 1900;private void open(){boolean ret = mSocketMng.openSokcet(GROUP_IP, LOCAL_PORT);log.e("openSokcet GROUP_IP = " + GROUP_IP + ", LOCAL_PORT = " + LOCAL_PORT + ", ret = " + ret);mSocketMng.startListenThread(this);updateText(GROUP_IP, LOCAL_PORT);mUnickSocketMng.openSokcet(12345);mUnickSocketMng.startListenThread();}private void close(){mSocketMng.closeSocket();log.e("closeSocket");clearText();mUnickSocketMng.closeSocket();}@Overridepublic void onDataReceive(final String hostIP,final int port, final String data) {runOnUiThread(new Runnable() {@Overridepublic void run() {updateContent(hostIP, port, data);}});}@Overridepublic void onCheckedChanged(RadioGroup group, int checkedId) {switch(checkedId){case R.id.rb_open:openWifiBrocast();break;case R.id.rb_close:closeWifiBrocast();break;}}private void openWifiBrocast(){if (mMulticastLock == null){WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); mMulticastLock = wifiManager.createMulticastLock("multicast.test"); if (mMulticastLock != null){mMulticastLock.acquire(); log.e("openWifiBrocast");}} }private void closeWifiBrocast(){if (mMulticastLock != null){mMulticastLock.release();mMulticastLock = null;log.e("closeWifiBrocast");}}
}
绑定和发送的组播地址是239.255.255.250:1900,正是upnp组播地址
测试的时候软件要装两个手机上,测udp单播的话改下目标IP即可
Ok本文到此为止~-~
more brilliant,Please pay attention to my CSDN blog -->http://blog.csdn.net/geniuseoe2012