草庐IT

android - 发送广播 UDP 但在其他 Android 设备上不接收

coder 2023-06-09 原文

我正在尝试开发一个应用程序来发送一些广播消息并从其他 android 设备接收一些答案。我在接收来自其他设备的 UDP 消息时遇到了一些问题。我应该提到,这段代码在 Gingerbread 上有效,但在 JellyBean 上它不再有效,我不知道可能是什么问题。

这里是我发送广播消息的地方(我知道其他设备监听端口 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

我应该提到,这 2 个函数在 2 个不同的线程中是分开的,所以我可以同时发送和接收。

我还获得了以下锁:

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

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

我已经测试了消息是否使用wireshark和tcpdump发送并且它们被发送。而且,更奇怪的是,我收到了我发送的广播消息(但我丢弃了它们,因为我不需要处理自己发送的消息)但我没有收到从其他设备发送的广播消息(应该有格式相同,只是源地址和包含的消息不同,任何一种方式都不会影响广播消息)。

如果您有任何想法,请告诉我,因为我真的没有其他可以尝试的方法了。任何帮助,将不胜感激。谢谢!

编辑: 我已经进行了一些测试,即使当我在每部手机上运行 ifconfig wlan0 时,它也会显示类似

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

这意味着接口(interface)处于 Activity 状态并且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);

}

最佳答案

我通过使用此处描述的方法来计算广播地址来完成这项工作: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);
  }

关于android - 发送广播 UDP 但在其他 Android 设备上不接收,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17308729/

有关android - 发送广播 UDP 但在其他 Android 设备上不接收的更多相关文章

  1. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  2. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  3. ruby-on-rails - RSpec:避免使用允许接收的任何实例 - 2

    我正在处理旧代码的一部分。beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)endRubocop错误如下:Avoidstubbingusing'allow_any_instance_of'我读到了RuboCop::RSpec:AnyInstance我试着像下面那样改变它。由此beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)end对此:let(:sport_

  4. jquery - 我的 jquery AJAX POST 请求无需发送 Authenticity Token (Rails) - 2

    rails中是否有任何规定允许站点的所有AJAXPOST请求在没有authenticity_token的情况下通过?我有一个调用Controller方法的JqueryPOSTajax调用,但我没有在其中放置任何真实性代码,但调用成功。我的ApplicationController确实有'request_forgery_protection'并且我已经改变了config.action_controller.consider_all_requests_local在我的environments/development.rb中为false我还搜索了我的代码以确保我没有重载ajaxSend来发送

  5. ruby - 调用其他方法的 TDD 方法的正确方法 - 2

    我需要一些关于TDD概念的帮助。假设我有以下代码defexecute(command)casecommandwhen"c"create_new_characterwhen"i"display_inventoryendenddefcreate_new_character#dostufftocreatenewcharacterenddefdisplay_inventory#dostufftodisplayinventoryend现在我不确定要为什么编写单元测试。如果我为execute方法编写单元测试,那不是几乎涵盖了我对create_new_character和display_invent

  6. ruby-on-rails - 如何使用 Rack 接收 JSON 对象 - 2

    我有一个非常简单的RubyRack服务器,例如:app=Proc.newdo|env|req=Rack::Request.new(env).paramspreq.inspect[200,{'Content-Type'=>'text/plain'},['Somebody']]endRack::Handler::Thin.run(app,:Port=>4001,:threaded=>true)每当我使用JSON对象向服务器发送POSTHTTP请求时:{"session":{"accountId":String,"callId":String,"from":Object,"headers":

  7. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  8. ruby - 使用 Ruby 通过 Outlook 发送消息的最简单方法是什么? - 2

    我的工作要求我为某些测试自动生成电子邮件。我一直在四处寻找,但未能找到可以快速实现的合理解决方案。它需要在outlook而不是其他邮件服务器中,因为我们有一些奇怪的身份验证规则,我们需要保存草稿而不是仅仅发送邮件的选项。显然win32ole可以做到这一点,但我找不到任何相当简单的例子。 最佳答案 假设存储了Outlook凭据并且您设置为自动登录到Outlook,WIN32OLE可以很好地完成此操作:require'win32ole'outlook=WIN32OLE.new('Outlook.Application')message=

  9. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  10. SPI接收数据异常问题总结 - 2

    SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手

随机推荐