从 Android 应用程序向 ESP32 发送 UDP 数据包不起作用

问题描述 投票:0回答:1

我正在构建一个应该与 ESP32 通信的 Android 应用程序。设置如下:

  • ESP32 将自身配置为接入点
  • ESP32 定期通过 UDP 广播发送连接请求
  • APP将手机连接到ESP32的WiFi(凭证暂时硬编码)
  • APP收到连接请求

这就是我被困的地方:

  • APP 通过确认回复发送者(ESP32)。现在 ESP32 和 APP 应该互相认识了。

我用笔记本电脑加入了 WiFi,并通过 WireShark 观察流量。所有广播消息(以及许多其他内容)都是可见的,但是应用程序从不发送 UDP 数据包。

我非常确定 ESP32 端可以正常工作,每次我通过 python 从笔记本电脑发送 udp 数据包时,它们都会到达 ESP。 我这样设置接入点:

const IPAddress gateWay(192, 168, 1, 1);
const IPAddress localIP(192, 168, 1, 1);
const IPAddress subnet(0, 0, 0, 0);

void setup(){
  Serial.begin(115200);
  // sdUtils.begin();
  imu.begin(FILTER_UPDATE_RATE_HZ);

  // configure esp as access point
  WiFi.softAP(SSID, PASS);
  //WiFi.config(localIP, gateWay, subnet);
  WiFi.softAPConfig(localIP, gateWay, subnet);
  Serial.println(udp.begin(2255));
}

void loop(){
  // initiate connection
  while (!client.connected()) {
    Serial.println("Initializing connection");
    // broadcast IP via UDP broadcast
    String ipAddress = WiFi.localIP().toString();
    udp.beginPacket(WiFi.broadcastIP().toString().c_str(), 2255);
    udp.println(ipAddress);
    udp.endPacket();
      
    // parse answer
    int packetSize;
    unsigned long startTime = millis();
    do {
      packetSize = udp.parsePacket();
    } while (!packetSize && (millis() - startTime) < 5000);
    if (packetSize) {
      // read answer which is IP adress
      char buffer[packetSize];
      Serial.println(udp.remoteIP().toString());
      udp.read(buffer, packetSize);
      String phoneIP = buffer;
      Serial.println(phoneIP); 

      // Establish a TCP connection to the phone
      client.connect(phoneIP.c_str(), 8080);

      // Send data to the phone
      client.println("Hello from the ESP32!");
    } else {
      Serial.println("Server dindn't answer...");
    }
  }
}

这就是我尝试在 Android 应用程序中发送 UDP 包的方式:

public class Connectivity {
    private final Context context;
    private WifiManager wifiManager;
    private Handler handler;

    private DatagramSocket socket;


    public Connectivity(Context context) {

        this.context = context;
        this.handler = new Handler(Looper.getMainLooper());

        try {
            wifiManager = (WifiManager) this.context.getSystemService(Context.WIFI_SERVICE);
            socket = new DatagramSocket(2255);
            socket.setBroadcast(true);
        } catch (IOException e) {
            Log.e(TAG, "failed to create UDP socket", e);
        }
    }


    public void connectSensor(String ssid, String password) {

        // make sure wifi is enabled
        if (!wifiManager.isWifiEnabled()) {
            wifiManager.setWifiEnabled(true);
        }

        establishConAfterQ(ssid, password);
    }

    public void disconnectSensor() {
        if (wifiManager.isWifiEnabled()) {
            wifiManager.disconnect();
            wifiManager.setWifiEnabled(false);
        }
    }

    public void start() {
        new Thread(this::receive).start();
    }

    public void receive() {
        while (true) {
            byte[] buffer = new byte[128];
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

            try {
                socket.receive(packet);
            } catch (IOException e) {
                Log.e(TAG, "Failed to receive UDP packet", e);
                continue;
            }

            String message = new String(buffer, 0, packet.getLength());
            Log.d(TAG, "Received UDP packet: " + message.replace("\n", "") + " from IP address: " + packet.getAddress().toString() + " at port: " + packet.getPort());

            // Send the answer
            Log.i(TAG, "Sending Answer");
            String answer = "Heureka it works!!";
            byte[] data = answer.getBytes();
            DatagramPacket response = new DatagramPacket(data, data.length, packet.getAddress(), packet.getPort());

            try {
                socket.send(response);
            } catch (IOException e) {
                Log.e(TAG, "Failed to send UDP packet", e);
            }
        }
    }

我连接wifi的函数如下所示:

private void establishConAfterQ(String ssid, String password) {
        WifiEnterpriseConfig config = new WifiEnterpriseConfig();
        config.enableTrustOnFirstUse(true);
        config.setPassword(password);
        WifiNetworkSpecifier specifier = new WifiNetworkSpecifier.Builder()
                .setSsid(ssid)
                .setWpa2Passphrase(password)
                .build();
        NetworkRequest networkRequest = new NetworkRequest.Builder()
                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                .setNetworkSpecifier(specifier)
                .build();

        ConnectivityManager connectivityManager = (ConnectivityManager) this.context.getSystemService(Context.CONNECTIVITY_SERVICE);

        // Register a callback to listen for the connection result
        ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
            @Override
            public void onAvailable(android.net.Network network) {
                super.onAvailable(network);
                Log.d(TAG, "Connected to WiFi network: " + ssid);
            }

            @Override
            public void onUnavailable() {
                super.onUnavailable();
                Log.d(TAG, "Failed to connect to WiFi network: " + ssid);
            }
        };

        // Request the network connection
        connectivityManager.requestNetwork(networkRequest, networkCallback);
    }

奇怪的是,当我断开手机与电脑的连接并手动登录 WiFi 热点时,在短时间内一切都运行良好。但是,此后我无法重现此行为。

我是否缺少连接配置之类的内容,以致无法发送 UDP 命令?我已经在谷歌上进行了相当深入的搜索,但我没有找到任何东西。

更新 我发现我可以从android发送udp包到广播地址(255.255.255.255)或者到托管APP的手机的IP地址。但是,我无法访问除这些 IP 之外的任何 IP(或者至少我没有找到 IP)。那么android中是否内置了隐藏的防火墙?

感谢您的帮助!

java android networking udp esp32
1个回答
0
投票

android 里好像没有隐藏的防火墙。

我使用广播,但不使用(255.255.255.255)。

只需使用 wifiudp 类对象中的 localIP,并将第 4 个八位字节设置为 255,即仅与当前段相关。

© www.soinside.com 2019 - 2024. All rights reserved.