2013-06-25 54 views
11

Tôi đang cố phát triển một ứng dụng gửi một số tin nhắn quảng bá và nhận một số câu trả lời từ các thiết bị Android khác. Tôi gặp sự cố khi nhận tin nhắn UDP từ các thiết bị khác. Tôi nên đề cập rằng mã này làm việc trên Gingerbread nhưng trên Jellybean nó không hoạt động nữa và tôi không biết điều gì có thể là vấn đề.Gửi Broadcast UDP nhưng không nhận được trên các thiết bị Android khác

Đây là nơi tôi gửi tin nhắn quảng bá (Tôi biết các thiết bị khác lắng nghe trên cổng 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(); 
    } 

} 

Và đây là nơi mà tôi nhận được nó:

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 

tôi nên đề cập rằng 2 chức năng này tách biệt trong 2 luồng khác nhau để tôi có thể gửi và nhận đồng thời.

Tôi cũng có được khóa sau:

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(); 

Và các điều khoản trên các tập tin Manifest:

<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"/> 

Tôi đã thử nghiệm nếu các thông điệp được gửi bằng Wireshark và tcpdump và chúng được gửi. Hơn nữa, những gì thậm chí còn lạ hơn, tôi nhận được tin nhắn phát mà tôi gửi (nhưng tôi loại bỏ chúng vì tôi không cần xử lý các tin nhắn được gửi từ bản thân mình) nhưng tôi không nhận được tin nhắn được gửi từ các thiết bị khác (cần có cùng một định dạng, chỉ có địa chỉ nguồn sẽ khác và thông báo chứa, dù cách nào cũng không ảnh hưởng đến thông báo phát sóng).

Vui lòng cho tôi biết nếu bạn có bất kỳ ý tưởng nào vì tôi thực sự đã hết mọi thứ khác mà tôi có thể thử. Bất kỳ trợ giúp sẽ được đánh giá cao. Cảm ơn!

EDIT: Tôi đã thực hiện một số xét nghiệm và thậm chí nếu khi tôi chạy trên mỗi wlan0 điện thoại ifconfig và nó nói cái gì đó như

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

có nghĩa là giao diện đang hoạt động và địa chỉ IP được thiết lập và có thể nhận tin nhắn quảng bá và thông điệp đa hướng nhưng khi tôi sử dụng

    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"); 

Nó hiển thị trong máy chủ nhật ký không thể truy cập được.

Đây là nơi tôi bật 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

Lưu ý rằng một số các bộ định tuyến vô hiệu hóa DNS multicast theo mặc định. – yorkw

+0

oh ... Tôi phải đề cập đến rằng tôi đang ở trong một wifi adhoc – Lara

+0

Bạn có thể muốn xem bài đăng này: http://stackoverflow.com/a/16208617/1028256 Nó nói rằng một số trình điều khiển wifi có thể vô hiệu hóa máy thu phát sóng, nhưng trong trường hợp đó nó xảy ra sau khi tiếp tục từ chế độ ngủ. – Mixaz

Trả lời

1

Tôi đã xem qua bài viết của bạn khi cố gắng để giải quyết một vấn đề tương tự. Bạn có làm công cụ của mình không?

Trong trường hợp của tôi, tôi đã cố gắng để có được một Nexus 7 (gen đầu tiên với Jelly Bean 4.3) và Nexus One (Gingerbread 2.3.6) nói chuyện với nhau thông qua UDP. Ban đầu ứng dụng của tôi, chạy trên cả hai thiết bị, sẽ liên kết thành công nhưng chỉ với giao tiếp một chiều từ điện thoại đến máy tính bảng. Tôi chỉ có một sự cho phép tại chỗ trong tệp kê khai: INTERNET. Giao tiếp từ máy tính bảng tới điện thoại bắt đầu hoạt động sau khi tôi đã thêm quyền ACCESS_NETWORK_STATE vào tệp kê khai. Vì vậy, vì một lý do nào đó, Nexus 7 chỉ hài lòng với quyền INTERNET cho cả việc gửi và nhận các gói UDP (tốt, thực hiện cụ thể của tôi về nó, ít nhất).Nexus One sẽ chỉ gửi với quyền INTERNET nhưng sẽ không nhận được trừ khi được cấp quyền ACCESS_NETWORK_STATE.

Mã của bạn trông giống như của tôi (tôi không nhận ra các cuộc gọi "TIỆN ÍCH" của bạn). Trong trường hợp của tôi, tuy nhiên, với mục đích thử nghiệm, tôi đã mã hóa cứng địa chỉ quảng bá (192.168.n.255). Tôi đang ở trên một điểm truy cập trong khi bạn đang ở trên một mạng adhoc. Có lẽ điều đó cũng có một số hiệu ứng.

12

tôi đã làm việc này bằng cách sử dụng một phương pháp mô tả ở đây để tính toán địa chỉ quảng bá: https://code.google.com/p/boxeeremote/wiki/AndroidUDP

Dưới đây là nhận của tôi:

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()); 
} 

Và đây là người gửi tôi:

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

Mã này chỉ hoạt động nếu các thiết bị trên cùng một mạng cục bộ? – zer0uno

+0

Có, chính xác là – caspii

+0

đã xác minh trên Android 5.1.1 và Android 7.1.2 –