0

我正在努力解决一个问题,即 ESP32 作为 AP 运行,AsyncTCP 连接多个 ESP32 客户端。AP 接收一些 JSON 数据并回复一些 JSON 数据。如果没有 handleData() 函数,代码可以 100% 正常运行,没有任何问题。当没有客户端连接时,堆是静态的,并且仅在客户端开始连接时才会出现问题。

任何人都可以看到我的代码中可能导致堆损坏或其他内存异常的任何内容吗?

static void handleData(void* arg, AsyncClient* client, void *data, size_t len) {
int i = 0, j = 0;
char clientData[CLIENT_DATA_MAX];
char packetData[len];
char *packetBuf;

   packetBuf = (char *)data;
   clientData[0] = '\0';

   for (i=0;i <= len;i++) {
      packetData[j] = packetBuf[i]; //packetBuf[i];

      if ((packetData[j] == '\n') || (i == len)) {
         packetData[j] = '\0';
         if ((j > 0) && (packetData[0] != '\n') && (packetData[0] != '\r')) {
            // See sensorData() below...
            parseData.function(packetData, clientData);
            if (clientData != NULL) {
               // TCP reply to client
               if (client->space() > 32 && client->canSend()) {
                 client->write(clientData);
               }
            }
         }
         j = 0;
      } else
         j++;
   }
}

void sensorData(void *data, void *retData) {
StaticJsonDocument<CLIENT_DATA_MAX> fields;
StaticJsonDocument<CLIENT_DATA_MAX> output;
char sensor[15] = "\0";
char MAC[18] = "\0";
char value[20] = "\0";
bool sendOK = false;

   memcpy((char *)retData, "\0", 1);
   DeserializationError error = deserializeJson(fields, (char *)data, CLIENT_DATA_MAX);
   if (error) {
      DEBUG_PRINTLN(F("deserializeJson() failed"));
      return;
   }

   if (fields["type"])
      strcpy(sensor, fields["type"]);

   switch (sensor[0]) {
      case 'C': 
         if (fields["value"])
            strcpy(value, fields["value"]);
         sendOK = true;
         break;
      case 'T': //DEBUG_PRINT(F("Temp "));
         setExtTempSensor(fields["value"]);
         sendOK = true;
         break;
      case 'N': 
         output["IT"] = intTempC; //Internal temp
         output["B1"] = battLevels[0];
         serializeJson(output, (char *)retData, CLIENT_DATA_MAX-1);
         break;
   } 
   if (sendOK) {
      output["Resp"] = "Ok";
      serializeJson(output, (char *)retData, CLIENT_DATA_MAX-1);
   }
   strcat((char *)retData, "\n");
}

static void handleNewClient(void* arg, AsyncClient* client) {
   client->setRxTimeout(1000);
   client->setAckTimeout(500);
   client->onData(&handleData, NULL);
   client->onError(&handleError, NULL);
   client->onDisconnect(&handleDisconnect, NULL);
   client->onTimeout(&handleTimeOut, NULL);
}

void startServer() {
  server = new AsyncServer(WIFI_SERVER_PORT);
  server->onClient(&handleNewClient, &server)
}


4

2 回答 2

0

要么你应该声明packetData为长度len + 1,要么你的for循环应该迭代 until i < len。因为索引从 0 开始,packetData[len]实际上是 byte ,所以如果数组只有chars长len + 1,那么当你存储一些东西时,你会覆盖一些随机的东西。随机的东西可能是存储在 中的指针,这很容易导致堆损坏。packetData[len]lenpacketBuf

您应该始终使用strncpy()并且永远不要使用strcpy(). 同样使用strncat()而不是strcat(). 不要依赖于是否正确地完成了数学运算或依赖于不会随着代码的发展而改变的大小。strncpy()并将strncat()防止溢出。您需要传递一个长度sensorData()来做到这一点,但sensorData()不应该对retData.

你的测试

    if (clientData != NULL) {

永远不会失败,因为clientData是数组的地址并且不能改变。我不确定您要在这里测试什么,但这if总会成功。

你可以写:

char sensor[15] = "";

您不需要显式分配其中包含空字节的字符串。

memcpy((char *)retData, "\0", 1);

相当于

((char *)retData)[0] = '\0';

声明retData参与到void *的论点有什么意义sensorData()?您的代码以 a char*before 调用开始sensorData(),并将其用作char*inside sensorData()void *旨在成为传递指针而不用担心它们的类型的逃生舱口。您在这里不需要它,因此最终需要额外的演员阵容char*。只需将参数声明为char*,不要担心再次转换它。

您没有共享调用的代码,handleData()因此这些函数之外很可能存在问题。

于 2020-06-22T15:04:26.910 回答
0

在 ESP32 上使用 AsyncTCP 存在多个问题。堆问题、套接字问题、断言问题、ACK 超时、连接超时等。使用与上面显示的 romkey 更改完全相同的代码交换到 AsyncUDP,解决了我的所有问题。(仅使用 romkey 的修复程序并不能解决我在使用 AsyncTCP 时遇到的错误。)我认为问题不在于 AsyncTCP,而在于 ESP32 库。

于 2020-06-25T19:59:12.043 回答