关于dlna开发使用的若干故障排除

鉴于此前博主发表过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单播的接收

对于dmrdms如果无法接收组播消息则意味着无法响应客户端的searh消息

对于dmpdmc如果无法接收组播则得不得dmrdms的上线下线消息,如果连udp单播接收都有问题,那么发出去的search消息即便对方有回应也接收不到,这些都会造成设备找不到或是搜索不稳定的问题

(当然同一个设备上的两个应用之间通讯不存在上述问题)

 

3.丢包问题

不论是udp组播还是udp单播,在路由器传输过程中都有可能丢包,所以为了尽量避免这种情况,可以在进行组播通知或是搜索的时候多发几次包(比如三次)

当然也不宜过多,否则会造成网络拥塞影响性能,这也引申出另一个问题,若是在网络环境较为复杂的路由器下测试dlna性能是很不理想的(丢包严重)

 

4.人品问题

         简单来说就是丫的两个设备明明没在一个局域网,还嚷嚷着为什么设备找不到

尤其是设备在使用wifi接入条件下,如果wifi不稳定断开了,很可能就连上另一个wifi网了,再说博主的代码有问题LZ就要骂人了关于dlna开发使用的若干故障排除


基本上第二点是需要大家注意的,不论是服务端应用还是客户端应用

早些时候可能因为没加上组播锁的缘故,所以会有类似问题,不过写这篇文章的时候

相关code已经commit修改了,请大家下载更新

在反编译了诸如搜狐视频,网易视频等APK发现它们并未添加组播锁,作为dmc就可能导致无法收到dmrnotify组播消息,只能依赖search机制,正如前面所说,部分手机甚至连udp单播都会受影响,那么搜索不到设备也就不奇怪了。

这时候又想使用这些软件怎么办?刚刚给大家推荐了一款软件bubbleupnp,它有一种神奇的魔力,可以打开系统组播锁,让其他应用也能正常接收到组播(LZ至今尚不明白它是怎么做到的,有知道的麻烦告知)


另外附上一个用于组播测试的demo

下载地址:http://download.csdn.net/detail/geniuseoe2012/6847963


截图:

关于dlna开发使用的若干故障排除



代码片段

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;
		}
		@Override
		public 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()){

			@Override
			public 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;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
			
		setupViews();
		initData();
	}

	

	@Override
	protected 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("");
	}
	
	@Override
	public 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();
	}

	

	@Override
	public void onDataReceive(final String hostIP,final int port, final String data) {
		runOnUiThread(new Runnable() {
			@Override
			public void run() {
				updateContent(hostIP, port, data);
			}
		});
	}



	@Override
	public 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 


关于dlna开发使用的若干故障排除

上一篇:NYIST_2013寒假ACM集训队练习赛(2)


下一篇:仿百度文库文档上传页面的多级联动分类选择器