2013-06-25 54 views
11

我想開發一個應用程序,發送一些廣播消息,並從其他Android設備接收一些答案。我從其他設備接收UDP消息時遇到了一些麻煩。我應該提到這個代碼在薑餅上工作,但在JellyBean上它不再工作,我不知道可能是什麼問題。發送廣播UDP,但沒有收到它在其他Android設備

這裏是我發送廣播消息(我知道其他設備偵聽端口5000):

private void sendUDPMessage(String msg) { 

    try { 
     DatagramSocket clientSocket = new DatagramSocket(); 

     clientSocket.setBroadcast(true); 
     InetAddress address = InetAddress.getByName(Utils.getBroadcastAddress()); 

     byte[] sendData; 

     sendData = msg.getBytes(); 
     DatagramPacket sendPacket = new DatagramPacket(sendData, 
       sendData.length, address, 5000); 
     clientSocket.send(sendPacket); 

     clientSocket.close(); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 

} 

這裏是我接受它:

private void start_UDP() 
{ 
    try { 
      serverSocketUDP = new DatagramSocket(5000); 
     } 
    catch (Exception e) { 

     Log.i(LOGTAG, "Exception opening DatagramSocket UDP"); 
    } 

    final byte[] receiveData = new byte[1024]; 


    while(runningUDP) { 
     Log.d(LOGTAG, "Waiting for Broadcast request in ServerUDP."); 

     final DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); 

     serverSocketUDP.receive(receivePacket); 


       byte[] sendData = new byte[1024]; 
       InetAddress address = receivePacket.getAddress(); 
       int port = receivePacket.getPort(); 
       if(!receivePacket.getAddress().getHostAddress().equals(Utils.getLocalIpAddress())) 
       { 
        String req = new String(receivePacket.getData(), 0, receivePacket.getLength()); 


        Log.d(LOGTAG, "Received UDP message : "+req+" from: "+receivePacket.getAddress().getHostAddress()); 
       } 
         }// while ends 
     }//method ends 

我應該指出,這兩個函數在兩個不同的線程中是分開的,所以我可以同時發送和接收。

我還獲得以下鎖:

powerManager =(PowerManager)context.getSystemService(Context.POWER_SERVICE); 
    wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK ,LOGTAG); // PARTIAL_WAKE_LOCK Only keeps CPU on 
    wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE); 
    wifiLock = wifiManager.createWifiLock(3, LOGTAG); 
    multicastLock = wifiManager.createMulticastLock(LOGTAG); 

    wakeLock.acquire(); 
    multicastLock.acquire(); 
    wifiLock.acquire(); 

而且在清單文件的權限:

<uses-permission android:name="android.permission.INTERNET" /> 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> 
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> 
<uses-permission android:name="android.permission.WAKE_LOCK" /> 
<uses-permission android:name="android.permission.WRITE_SETTINGS"/> 
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/> 

如果消息是使用Wireshark的和tcpdump的送我已經測試,他們被髮送。此外,更奇怪的是,我收到了我發送的廣播消息(但由於我不需要處理自己發送的消息,我放棄了它們),但我沒有收到其他設備發送的廣播消息(應該有相同的格式,只有源地址會有所不同,並且包含消息,無論哪種方式都不應該影響廣播消息)。

請讓我知道,如果你有任何想法,因爲我真的跑了我可以嘗試的任何東西。任何幫助,將不勝感激。謝謝!

編輯: 我已經做了一些測試,即使當我在每個手機的ifconfig爲wlan0的運行,並且說像

ifconfig wlan0 
    wlan0: ip 169.254.17.28 mask 255.255.0.0 flags [up broadcast multicast] 

這意味着該接口是活躍和IP設置和可以接收廣播消息和多播消息,但是當我使用

    InetAddress in=InetAddress.getByName("169.254.17.28"); 
      if (in.isReachable(1000)) 
       Log.i(LOGTAG, "host is reachable"); 
      else 
       Log.i(LOGTAG, "host is not reachable"); 

它在日誌中顯示主機無法訪問。

這是我打開了Wi-Fi

private void startWifiAdhoc() { 

    WifiManager wifiManager =  (WifiManager)SharingFileService.context.getSystemService(Context.WIFI_SERVICE); 
    String command=""; 
    if (condWifiAdhoc == false) { 

     condWifiAdhoc=true; 
     wifiInterface = Utils.getWifiInterface(); 


     wifiManager.setWifiEnabled(true); 
     localIP = Utils.getLinkLocalAddress(); 
    } 
    else 
    { 
     wifiManager.setWifiEnabled(true); 
     localIP = Utils.getLinkLocalAddress(); 
    } 
     // Set wifi ad-hoc 
     command = context.getFilesDir().getPath() 
       + "/iwconfig " + wifiInterface + " mode ad-hoc essid " 
       + "mcp" + " channel " + "1" + " commit\n"; 

     Log.i(LOGTAG, command); 
     Utils.rootExec(command); 


     Log.i(LOGTAG, "Ip address used :" + localIP); 
     command = context.getFilesDir().getPath() 
       + "/ifconfig " + wifiInterface + " " + localIP 
       + " netmask 255.255.0.0 up\n"; 



     Log.i(LOGTAG, command); 
     Utils.rootExec(command); 

} 
+0

注意一些路由器默認禁用多播DNS。 – yorkw

+0

哦...我必須提到,我在一個wifi adhoc – Lara

+0

你可能想看看這篇文章:http://stackoverflow.com/a/16208617/1028256它說,一些WiFi驅動程序可以禁用廣播接收器,但在那種情況下,它會在從睡眠模式恢復後發生。 – Mixaz

回答

1

試圖解決類似問題,當我遇到你的文章就來了。你的東西有用嗎?

在我的情況下,我一直試圖讓Nexus 7(第一代Jelly Bean 4.3)和Nexus One(薑餅2.3.6)通過UDP互相交談。最初,我的應用程序在兩臺設備上運行,都可以成功連接,但只能通過手機與平板電腦進行單向通信。我在清單中只有一個許可:INTERNET。一旦我將ACCESS_NETWORK_STATE權限添加到清單中,平板電腦與手機之間的通信就開始運作。

因此,出於某種原因,Nexus 7對於發送和接收UDP數據包(以及我的特定實現至少)的INTERNET許可感到滿意。Nexus One將僅以INTERNET權限發送,但除非還提供了ACCESS_NETWORK_STATE權限,否則不會接收。

您的代碼看起來與我的類似(但我不認識到您的「UTILS」調用)。但就我而言,爲了測試目的,我對廣播地址(192.168.n.255)進行了硬編碼。當您在adhoc網絡上時,我正在接入點上。也許這也有一些效果。

12

我得到這個使用上面介紹的方法來計算廣播地址工作:https://code.google.com/p/boxeeremote/wiki/AndroidUDP

這裏是我的接收器:

try { 
    //Keep a socket open to listen to all the UDP trafic that is destined for this port 
    socket = new DatagramSocket(Constants.PORT, InetAddress.getByName("0.0.0.0")); 
    socket.setBroadcast(true); 

    while (true) { 
    Log.i(TAG,"Ready to receive broadcast packets!"); 

    //Receive a packet 
    byte[] recvBuf = new byte[15000]; 
    DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length); 
    socket.receive(packet); 

    //Packet received 
    Log.i(TAG, "Packet received from: " + packet.getAddress().getHostAddress()); 
    String data = new String(packet.getData()).trim(); 
    Log.i(TAG, "Packet received; data: " + data); 

    // Send the packet data back to the UI thread 
    Intent localIntent = new Intent(Constants.BROADCAST_ACTION) 
      // Puts the data into the Intent 
      .putExtra(Constants.EXTENDED_DATA_STATUS, data); 
    // Broadcasts the Intent to receivers in this app. 
    LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent); 
    } 
} catch (IOException ex) { 
    Log.i(TAG, "Oops" + ex.getMessage()); 
} 

這是我的發件人:

public void sendBroadcast(String messageStr) { 
    // Hack Prevent crash (sending should be done using an async task) 
    StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); 
    StrictMode.setThreadPolicy(policy); 

    try { 
     //Open a random port to send the package 
     DatagramSocket socket = new DatagramSocket(); 
     socket.setBroadcast(true); 
     byte[] sendData = messageStr.getBytes(); 
     DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, getBroadcastAddress(), Constants.PORT); 
     socket.send(sendPacket); 
     System.out.println(getClass().getName() + "Broadcast packet sent to: " + getBroadcastAddress().getHostAddress()); 
    } catch (IOException e) { 
     Log.e(TAG, "IOException: " + e.getMessage()); 
    } 
    } 

    InetAddress getBroadcastAddress() throws IOException { 
    WifiManager wifi = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); 
    DhcpInfo dhcp = wifi.getDhcpInfo(); 
    // handle null somehow 

    int broadcast = (dhcp.ipAddress & dhcp.netmask) | ~dhcp.netmask; 
    byte[] quads = new byte[4]; 
    for (int k = 0; k < 4; k++) 
     quads[k] = (byte) ((broadcast >> k * 8) & 0xFF); 
    return InetAddress.getByAddress(quads); 
    } 
+0

僅當設備位於同一本地網絡上時,此代碼是否工作? – zer0uno

+0

是的,這是正確的 – caspii

+0

在Android 5.1.1和Android 7.1.2上驗證 –