Клиент Android транслирует UDP-запрос на сервер IP, получая эхо вместо ответа - PullRequest
1 голос
/ 30 октября 2019

У меня есть встроенная система (ESP32), которая может переключаться с Wi-Fi-клиента на Wi-Fi Access Point с помощью тумблера и иметь возможность общаться через TCP с приложением Android для управления реле и прочим. Я начал проект с работы в качестве точки доступа, и весь проект работал нормально. Моя проблема заключается в том, что когда я реализовал обнаружение UDP для того, чтобы он работал в каждой сети, я хотел, чтобы мой ESP32 получил запрос UDP и инициировал передачу по TCP, но мое приложение только получает мое сообщение запроса (эхо) в качестве ответа. Пожалуйста, укажите мне причину этого и как это исправить.

Я использовал этот ответ , который указал это видео , чтобы попытаться закодировать обмен сообщениями UDP.

Также я использую эту библиотеку GitHub с эту реализацию UDP-коммуникаций . Я пытался этот раньше, и он не работал, поэтому я изменил его, надеясь, что это решит проблему. В обеих библиотеках я нашел мало информации об обмене сообщениями клиент + сервер и не нашел примеров в обнаружении UDP.

Первая часть кода - это минимальная функция моего приложения, которая запускает UDP-запрос. Первая функция условия говорит, что мое устройство подключено к сети Wi-Fi:

if (wifiTest.haveNetworkConnection((ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE))){
    try {
        UDP_DiscoverServer discoverServer = new UDP_DiscoverServer();
        ipDescoberto = discoverServer.execute(Tela_Selecao_Bancada.this, "Se4rch_f0r_coNnect1on_with_server_Device\r\n").get(); //this line is supposed to give back my embedded devide ip string
    } catch (InterruptedException | ExecutionException  e) {
        e.printStackTrace();
    }
    if (ipDescoberto != null){
        /*  .
            .
        Some code
            .
            .   */
    } else {
        final  String failedText = "No device connection detected. Check if your phone and device share the same network.";
        Snackbar.make(findViewById(android.R.id.content), failedText, Snackbar.LENGTH_LONG).show();
    }
}

Теперь, все еще в моем приложении, это мой частный AsyncTask, который будет выполнять запрос UDP и возвращать мой ответ:

private static class UDP_DiscoverServer extends AsyncTask<Object, Void, String> {

    private Inet4Address ipAddress;
    private int port;
    private String resp = null;
    private DatagramSocket datagramSocket;
    private WeakReference<Tela_Selecao_Bancada> activity;


    public UDP_DiscoverServer() {
        super();
        this.ipAddress = getBroadcast();
        this.port = 39600;
    }

    @Override
    protected String doInBackground(Object... args) {
        activity = new WeakReference<>((Tela_Selecao_Bancada) args[0]);
        String mensagem = (String) args[1];
        try {
            datagramSocket = new DatagramSocket(port);
            datagramSocket.setBroadcast(true);
            String CRLF = "\r\n";
            if (!mensagem.endsWith(CRLF)) {
                mensagem += CRLF;
            }
            DatagramPacket packetSend = new DatagramPacket(mensagem.getBytes(), mensagem.length(), ipAddress, port);
            datagramSocket.send(packetSend);
            datagramSocket.setReceiveBufferSize(1024);
            byte[] respBuffer = new byte[100];
            DatagramPacket packetReceive = new DatagramPacket(respBuffer, respBuffer.length);
            datagramSocket.receive(packetReceive);

            resp = new String(packetReceive.getData(), 0, packetReceive.getLength()); 
            if (resp.length() > 10 && resp.startsWith("Hell0_client")) //this line shows the debbug result
                return resp;
        } catch (IOException e) {
            //TODO: For DEBUG purpose only. Comment the following line before publishing the app
            Log.d("erroPeerConn", "error trying to discover connection");
            e.printStackTrace();
        } catch (NullPointerException e){
            e.printStackTrace();
            Handler handler = new Handler();
            handler.post(new Runnable() {
                @Override
                public void run() {
                    Snackbar.make(activity.get().findViewById(android.R.id.content), "Error trying to send broadcast. Check your WiFi connection.", Snackbar.LENGTH_LONG);
                }
            });
        }
        return null;
    }

    @Override
    protected void onPostExecute(String s) {
        datagramSocket.close();
        if (activity != null) activity.clear();
        super.onPostExecute(s);
    }

    private Inet4Address getBroadcast(){
        try {
            Enumeration<NetworkInterface> niEnum = NetworkInterface.getNetworkInterfaces();
            while (niEnum.hasMoreElements()) {
                NetworkInterface ni = niEnum.nextElement();
                if (!ni.isLoopback()) {
                    if (!ni.getInterfaceAddresses().isEmpty()) {
                        InterfaceAddress interfaceAddress = ni.getInterfaceAddresses().get(0);
                        return (Inet4Address) Inet4Address.getByName(interfaceAddress.getBroadcast().toString().substring(1));
                    }
                }
            }
        } catch (SocketException | UnknownHostException e) {
            e.printStackTrace();
        }
        return null;
    }
}

Наконец, это мой минимальный «код» ESP32. На самом деле это просто функция состояния машины, которая будет постоянно выполняться до тех пор, пока клиент не появится (сделайте UDP-запрос):

#include <WiFi.h>
#include <string.h>
#include <WiFiUdp.h>

#define PORT_DISCOVER     39600

const char *MENSAGEM_DISCOVER = "Se4rch_f0r_coNnect1on_with_server_Device\r\n";
WiFiUDP serverDiscover;
WiFiClient client;
IPAddress clientTCP_IP;

boolean broadcastListening(){
  if (!listeningUmaVez){
    serverDiscover.begin(PORT_DISCOVER);
    listeningUmaVez = true;
    Serial.print("UDP Listening on Port: ");
    Serial.println(PORT_DISCOVER);
  }
  if (!client){
    //processing incoming packet, must be called before reading the buffer
    serverDiscover.parsePacket();
    //receive response from client
    char readBuffer[100] = '\0';
    int readLength = serverDiscover.read(readBuffer, 100);
    if(readLength > 0){
      Serial.print("Cliente Android para ESP: ");
      Serial.println(*&readBuffer);
      if (strcmp(MENSAGEM_DISCOVER, *&readBuffer) == 0){
        Serial.println("Conexão detectada:");
        Serial.print("From: ");
        Serial.print(serverDicover.remoteIP());
        clientTCP_IP = serverDicover.remoteIP();
        Serial.print(":");
        Serial.print(serverDicover.remotePort());
        Serial.print(", Length: ");
        Serial.print(packet.length());
        Serial.println();
        //reply to the client
        serverDiscover.beginPacket(clientTCP_IP, PORT_DISCOVER);
        char auxChar[50] = "Hell0_client_4ndr0id.This_1s_My_IP_";
        strcat(auxChar, IPAddressToCharArray(lastConnectionType == HIGH?WiFi.localIP():WiFi.softAPIP())); // lastConnectionType is an input that says if it is an AP or Station.
        Serial.print("Response string: ");
        Serial.println(*&auxChar);
        serverDiscover.write((const uint8_t*)*&auxChar, strlen(auxChar));
        serverDiscover.endPacket();
        //serverDiscover.stop();
        return true;
      }
    }
  }
  return false;
}

Это переменные отладки Android Studio в показанной выше строке кода:

mensagem = "Se4rch_f0r_coNnect1on_with_server_Device\r\n"
CRLF = "\r\n"
datagramSend = {DatagramPacket@4719} 
respBuffer = {byte[100]@4721} 
datagramReceive = {DatagramPacket@4722} 
resp = "Se4rch_f0r_coNnect1on_with_server_Device\r\n"
...