Arduino不支持使用websocket协议发送超过65535个字符的消息

Arduino does not support messages larger than 65535 characters using websocket protocol?

本文关键字:65535个 字符 消息 不支持 websocket 协议 Arduino      更新时间:2023-10-16

我正在使用以下Arduino websocket库,当我尝试发送超过65535个字符的消息时遇到了问题,我收到了握手失败错误
只要消息不超过这个长度,它就可以完美地进行

图书馆的主页上有一张纸条,上面写着:

Because of limitations of the current Arduino platform (Uno at the time of this writing),   
 this library does not support messages larger than 65535 characters.   
 In addition, this library only supports single-frame text frames.   
 It currently does not recognize continuation frames, binary frames, or ping/pong frames.

在名为WebSocketClient.h的客户端头文件中,有以下注释:

// Don't allow the client to send big frames of data. This will flood the arduino memory and might even crash it.  
    #ifndef MAX_FRAME_LENGTH
    #define MAX_FRAME_LENGTH 256
    #endif  

我使用这个旧库是因为它是我在Arduino WIFI屏蔽上唯一使用的库,我找不到其他支持WIFI屏蔽的库,因为大多数webpacket库都是为Arduino Eathernet屏蔽而写的,而我没有。

我的Arduino代码是

/*DS18 Libs*/
#include <dht.h>
#include <OneWire.h>
#include <DallasTemperature.h>
/*Websocket Libs*/
#include <WebSocketServer.h>
#include <WebSocketClient.h>
#include <sha1.h>
#include <MD5.h>
#include <global.h>
#include <Base64.h>
#include <SPI.h>
#include <WiFiUdp.h>
#include <WiFiServer.h>
#include <WiFiClient.h>
#include <WiFi.h>
#include <string.h>
char ssid[] = "AMM";
char pass[] = "027274792";
int status = WL_IDLE_STATUS;
IPAddress server(192, 168, 1, 3);
WiFiClient WiFiclient;
WebSocketClient WSclient;
// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)  
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);
//Humidture
dht DHT;
#define DHT11_PIN 4
void setup()
{
   Serial.begin(9600);
    while (!Serial) {
          ; // wait for serial port to connect. Needed for Leonardo only
}
 //check for the presence of the shield:
if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue:
    while (true);
}
// attempt to connect to Wifi network:
while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to WPA SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network:    
    status = WiFi.begin(ssid, pass);
}
// you're connected now, so print out the data:
Serial.print("You're connected to the network");
/* Connect to the websocket server*/
if (WiFiclient.connect(server, 8080)) {
    Serial.println("Connected");
}
else {
    Serial.println("Connection failed.");
    while (1) {
        // Hang on failure
    }
}
// Handshake with the server
WSclient.path = "/MyServer/endpoint/testtest/device/d6220ae7-caa9-48b5-92db-630c4c296ec4";
WSclient.host = "192.168.1.3:8080";
if (WSclient.handshake(WiFiclient)) {
    Serial.println("Handshake successful");
}
else {
    Serial.println("Handshake failed.");
    while (1) {
        // Hang on failure
    }
}
/*DS18*/
sensors.begin();
 }
void loop()
{   
     WSclient.sendData("{"service_code":"89c4da72-a561-47db-bf62-8e63f8c4bbf0","data":[" + getHumidtureValue() + "],"service_type":"TemperatureHumidityAnalysis"}");
     WSclient.sendData("{"service_code":"bdc0f984-6550-4712-881f-b09071da5a73","data":" + getCBodyTempretureValue() + ","service_type":"TemperatureGaugeMonitor"}");
     //line-3 commented WSclient.sendData("{"service_code":"8c212432-a86e-4c18-a956-9dc0dbb648d4","data":[" + getHumidtureValue() + "],"service_type":"HumidityGaugeMonitor"}");
}
 String getCBodyTempretureValue()
 {
     sensors.requestTemperatures(); // Send the command to get temperatures
     char charVal[10];
     return dtostrf(sensors.getTempCByIndex(0), 4, 2, charVal);
 }
 String getHumidtureValue()
 {
      String str = "";
      for (int i = 0; i < 2; i++)
      {
         int chk = DHT.read11(DHT11_PIN);
         switch (chk)
         {
            case DHTLIB_OK:
               Serial.println("OK,t");
               break;
            case DHTLIB_ERROR_CHECKSUM:
               Serial.println("Checksum error,t");
               break;
            case DHTLIB_ERROR_TIMEOUT:
               Serial.println("Time out error,t");
               break;
             default:
               Serial.println("Unknown error,t");
               break;
           }
           char charVal[10];
           double tempF = (DHT.temperature * 9) / 5 + 32;
           str = dtostrf(tempF, 3, 1, charVal);
           str = str + "," + dtostrf(DHT.humidity, 3, 1, charVal);
           Serial.println(str);
           delay(200);
     }
     return str;
   }

上面的代码运行得很好,当我取消注释循环函数中的第三条send语句时,我得到了握手失败的错误。

-考虑到这个库是一个旧库,为新版本的Arduino板修改MAX_FRAME_LENGTH的值是否安全
-还有比这个更好的库可以支持WiFi屏蔽上的websocket吗?

任何解决方案或想法都将不胜感激。

提前谢谢。

如果没有查看库的代码,更改最大帧长度可能是不安全的,因为websocket协议根据有效载荷长度的不同对其进行编码:

有效载荷长度:7位、7+16位或7+64位。

"有效载荷数据"的长度,以字节为单位:如果0-125,则为有效载荷长度。如果是126,则被解释为16位无符号整数的以下2个字节是有效载荷长度。如果为127,则解释为64位无符号整数(最高有效位必须为0)的以下8个字节为有效载荷长度。

当库表示不支持65535字节以上的有效负载长度时,这可能意味着它没有64位长度编码的实现。

经过多次尝试,程序的行为非常奇怪,这让我抓狂,我发现问题是我在程序中使用了太多字符串,这使得Arduino Uno很容易耗尽RAM。

我收到握手失败错误的主要原因是Arduino无法读取握手响应消息的"Sec-Webocket-Accept"标头(以及许多其他标头),我通过在服务器上调试代码来确保它们已发送。

事实上,这个问题和许多其他奇怪的行为一直在发生,直到我减少了程序运行期间使用的内存量。