У меня есть встроенная система (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"