您的位置:首页 > 移动开发 > Android开发

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

2014-01-14 18:23 567 查看
鉴于此前博主发表过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;
}
@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 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android upnp dlna 组播