如何让 java 应用程序与 ESP32 开发板通信?

How do I make a java app communicate with an ESP32 board?

我一直在尝试在 ESP32 开发板和 Java 服务器之间建立 TCP 套接字连接。建立连接后,我想让服务器发一个数据包给ESP32请求它的ID(我用ID来标识客户端,因为客户端会越来越多),但是服务器好像没有传输任何东西(ESP32 没有收到任何东西)。我什至尝试使用 Wireshark 来跟踪数据包,但在连接后,看不到任何消息。对于可怕的代码感到抱歉,在通信编程方面,我仍然是初学者。预先感谢您的帮助。

这是 ESP32 的代码:

#include <WiFi.h>

WiFiClient client;

// network info
char *ssid = "SSID";
char *pass = "Password";

// wifi stats
int wifiStatus;
int connAttempts = 0;

// Client ID
int id = 128;

IPAddress server(192,168,1,14);
int port = 3241;

String inData;

void setup() {
  Serial.begin(115200); // for debug

  // attempting to connect to the network
  wifiStatus = WiFi.begin(ssid, pass);
  while(wifiStatus != WL_CONNECTED){
    Serial.print("Attempting to connect to the network, attempt: ");
    Serial.println(connAttempts++);
    wifiStatus = WiFi.begin(ssid, pass);
    delay(1000);
  }

  // info
  Serial.print("Connected to the network, IP address is: '");
  Serial.print(WiFi.localIP());
  Serial.print("', that took ");
  Serial.print(connAttempts);
  Serial.println(" attempt(s).");
  connAttempts = 0;

  // connection to the main server
  Serial.println("Starting connection to the server...");
  while(!client.connect(server, port)){
    Serial.print("Attempting connection to the server, attempt no. ");
    Serial.println(connAttempts++);
    delay(1000);
  }
  Serial.print("Connection successful after ");
  Serial.print(connAttempts);
  Serial.println(" attempt(s)!");
}

void loop() {
  if(client.available()){
    Serial.println("Incoming data!");
    inData = client.readString();
  }
  if(inData != ""){
    Serial.print("Incoming data: ");
    Serial.println(inData);

    if(inData == "REQ_ID"){
      String msg = "INTRODUCTION;"
      strcat(msg, m);
      client.print(msg);
    }
    inData = "";
  }
  if(!client.connected()){
    Serial.println("Lost connection to the server! Reconnecting...");
    connAttempts = 0;
    while(!client.connect(server, port)){
      Serial.print("Attempting connection to the server, attempt no. ");
      Serial.println(connAttempts++);
      delay(1000);
    }
    Serial.print("Reconnection successful after ");
    Serial.print(connAttempts);
    Serial.println(" attempt(s)!");
  }
  delay(10);
}

这是来自 Java 服务器的客户端处理程序 class:

package org.elektrio.vsd2020;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;

public class ClientHandler implements Runnable {

    public Socket netSocket;
    public BufferedInputStream in;
    public BufferedOutputStream out;

    private int clientID;

    public ClientHandler(Socket skt) throws IOException {
        this.netSocket = skt;

        this.in = new BufferedInputStream(this.netSocket.getInputStream());
        this.out = new BufferedOutputStream(this.netSocket.getOutputStream());
    }

    public void close() throws IOException{
        this.in.close();
        this.out.close();
        this.netSocket.close();
    }

    @Override
    public void run() {
        while(netSocket.isConnected()){
            try{
                byte[] arr = new byte[2048];
                in.read(arr);
                String[] input = new String(arr, StandardCharsets.US_ASCII).split(";");

                // if the message is tagged as "INTRODUCTION", it identifies a reply from the ESP32, which contains the client ID
                if(input[0].equals("INTRODUCTION")){
                    clientID = Integer.parseInt(input[1]);
                }
            }
            catch (IOException e) {
                System.out.println("[" + LocalDateTime.now() + " at ClientHandler] Exception at client ID '" + clientID + "'!");
                e.printStackTrace();
            }
        }
        System.out.println("[" + LocalDateTime.now() + " at ClientHandler] Client ID '" + clientID + "' disconnected!");
        Tools.clients.remove(this);
    }

    public int getID(){
        return clientID;
    }

    public int reqID() throws IOException{
        String req = "REQ_ID";
        out.write(req.getBytes(StandardCharsets.US_ASCII));
    }
}

主服务器class:

package org.elektrio.vsd2020;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {

    public static ServerSocket server;
    public static ServerSocket remoteAccessServer;

    public static ExecutorService pool;

    public static boolean serviceRunning = true;

    public static void main(String[] args) {
        try{
            // startup args
            int port = args.length > 0 ? Integer.parseInt(args[0]) : 3241;                  
            int maxClients = args.length > 1 ? Integer.parseInt(args[2]) : 10;

            // startup parameters info
            Tools.log("Main", "Server started with parameters: ");
            if(args.length > 0) Tools.log("Main", args);
            else Tools.log("Main", "Default parameters");

            // server socket and the threadpool, where the client threads get executed
            server = new ServerSocket(port);
            pool = Executors.newFixedThreadPool(maxClients);

            // main loop
            while(true){
                if(Tools.clients.size() < maxClients){

                    // connection establishment
                    Socket clientSocket = server.accept();
                    ClientHandler client = new ClientHandler(clientSocket);

                    Tools.log("Main", "New client connected from " + clientSocket.getRemoteSocketAddress());

                    // starting the client operation
                    pool.execute(client);
                    Tools.clients.add(client);
                    Thread.sleep(500);
                    client.reqID();
                }
            }
        }
        catch (IOException | InterruptedException ioe){
            Tools.log("Main", "IOException at MAIN");
            ioe.printStackTrace();
        }
    }
}

最后,工具 class

package org.elektrio.vsd2020;

import java.time.LocalDateTime;
import java.util.ArrayList;

public class Tools {

    public static ArrayList<ClientHandler> clients = new ArrayList<>();

    public static void log(String origin, String message){
        System.out.println("[" + LocalDateTime.now() + " at " + origin + "] " + message);
    }

    public static void log(String origin, String[] messages){
        for(String msg : messages) System.out.println("[" + LocalDateTime.now() + " at " + origin + "] " + msg);
    }

}

我有一些建议:

I- 您的服务器实现,即 while(true){... Thread.sleep(500); ... },类似于微控制器风格的编程。 Java 有更强大的套接字通信工具,例如反应式框架。我建议使用像 Netty 这样的框架:

Netty 4 User Guide

Introduction to Netty

学习这些可能需要一些努力,但它们的性能要好得多。

还有用于物联网系统的现代协议,例如 MQTT 甚至 RSocket。您可以使用它们代替普通的 TCP 连接。

II: 在物联网系统中,隔离问题非常重要。因此,在您的情况下,使用像 Hercules 这样的 TCP 终端工具会有很大帮助。这些工具既可以充当服务器也可以充当客户端;因此您可以使用它们代替 ESP32 和 Java 服务器并测试另一端是否正常工作。

III:在物联网通信中,尽量限制消息。因此,而不是 ESP32 和 Java 之间的这种转换:

ESP32:嗨

Java: 你好,你是谁?

。我的 ID 是 ...

。把数据传给我...

。这是数据...

使用这个:

ESP32:嗨。我是 ID .. 这是我的数据

服务器:好的,谢谢!