647 字
3 分钟
ESP32 WebsocketsClient连接wss协议的服务器
前言
- 硬件:ESP32-S3 开发板
- Websocket库:
gilmaimon/ArduinoWebsockets@^0.5.4 - 平台:arduino/PlatformIO
在准备讯飞的大模型前期测试,其api协议从ws替换为了wss后,需要对部分功能进行修改。
在使用官方的python测试案例实现后,移植到arduino上却始终无法连接成功,在逐步测试后最终将问题定位到库上:Arduino ESP32做Websocket client 连接WSS协议的服务器。
ESP32 没有对 client.setInsecure(); 做出响应,即在没有证书时程序无法正常进行,需要修改库的内容。
下面是大致的测试代码:
#include <Arduino.h>#include <WiFi.h>#include <ArduinoWebsockets.h>
using namespace websockets;WebsocketsClient client;const char* websockets_connection_string = "wss://xxxxxxxxxxxxxx";
void setup() { led_status_service.init();
Serial.begin(115200); while (!Serial) { /* code */ }
// 连接WiFi WiFi.begin(STA_SSID, STA_PASSWORD); Serial.println("正在连接到WiFI..."); while (WiFi.status() != WL_CONNECTED) { delay(600); Serial.print("-"); } Serial.println("WiFi 已连接"); Serial.println("IP 地址: "); Serial.println(WiFi.localIP()); delay(1000);
// Before connecting, set the ssl fingerprint of the server client.setInsecure(); // client.setCertificate(); // client.setCACert(); // client.setPrivateKey();
// Connect to server if (client.connect(websockets_connection_string)) { Serial.println("yes"); } else { Serial.println("no"); }
// Send a ping client.ping();}
void loop() { client.poll();
delay(1); // 避免空循环过快}修改方法
点击 client.connect 进入 .pio\libdeps\esp32-s3-devkitm-1\ArduinoWebsockets\src\websockets_client.cpp。
找到下面这段关于 wss 协议的连接方法:
#ifndef _WS_CONFIG_NO_SSL else if(doestStartsWith(url, "wss://")) { defaultPort = 443; protocol = "wss"; url = url.substr(6); //strlen("wss://") == 6
upgradeToSecuredConnection(); } else if(doestStartsWith(url, "https://")) { defaultPort = 443; protocol = "https"; url = url.substr(8); //strlen("https://") == 8
upgradeToSecuredConnection(); }#endif点击 upgradeToSecuredConnection 找到相关实现,并找到 ESP8266 和 ESP32 对不同证书的处理方法:
#ifdef ESP8266 if( this->_optional_ssl_fingerprint || (this->_optional_ssl_rsa_cert && this->_optional_ssl_rsa_private_key) || (this->_optional_ssl_ec_cert && this->_optional_ssl_ec_private_key) || this->_optional_ssl_trust_anchors || this->_optional_ssl_known_key ) { if(this->_optional_ssl_fingerprint) { client->setFingerprint(this->_optional_ssl_fingerprint); } if(this->_optional_ssl_trust_anchors) { client->setTrustAnchors(this->_optional_ssl_trust_anchors); } if(this->_optional_ssl_known_key) { client->setKnownKey(this->_optional_ssl_known_key); } if(this->_optional_ssl_rsa_cert && this->_optional_ssl_rsa_private_key) { client->setClientRSACert(this->_optional_ssl_rsa_cert, this->_optional_ssl_rsa_private_key); } if(this->_optional_ssl_ec_cert && this->_optional_ssl_ec_private_key) { client->setClientECCert(this->_optional_ssl_ec_cert, this->_optional_ssl_ec_private_key); } } else { client->setInsecure(); }#elif defined(ESP32) if(this->_optional_ssl_ca_cert) { client->setCACert(this->_optional_ssl_ca_cert); } if(this->_optional_ssl_client_ca) { client->setCertificate(this->_optional_ssl_client_ca); } if(this->_optional_ssl_private_key) { client->setPrivateKey(this->_optional_ssl_private_key); }#endif在 ESP32 中没有对无证书的情况进行处理,没有调用过 client->setInsecure();。
将对应代码修改成:
#elif defined(ESP32) if( this->_optional_ssl_ca_cert || this->_optional_ssl_client_ca || this->_optional_ssl_private_key ) { if(this->_optional_ssl_ca_cert) { client->setCACert(this->_optional_ssl_ca_cert); } if(this->_optional_ssl_client_ca) { client->setCertificate(this->_optional_ssl_client_ca); } if(this->_optional_ssl_private_key) { client->setPrivateKey(this->_optional_ssl_private_key); } } else { client->setInsecure(); }#endif到这里,client->setInsecure(); 会提示报错:类 "websockets::network::SecuredEsp32TcpClient" 没有成员 "setInsecure"C/C++(135)
找到 client 的定义:
auto client = new WSDefaultSecuredTcpClient;找到 WSDefaultSecuredTcpClient 的定义:
#ifndef _WS_CONFIG_NO_SSL // OpenSSL Dependent #define WSDefaultSecuredTcpClient websockets::network::SecuredEsp32TcpClient#endif //_WS_CONFIG_NO_SSL找到 websockets::network::SecuredEsp32TcpClient 的定义:
namespace websockets { namespace network { typedef GenericEspTcpClient<WiFiClient> Esp32TcpClient;
class SecuredEsp32TcpClient : public GenericEspTcpClient<WiFiClientSecure> { public: void setCACert(const char* ca_cert) { this->client.setCACert(ca_cert); }
void setCertificate(const char* client_ca) { this->client.setCertificate(client_ca); }
void setPrivateKey(const char* private_key) { this->client.setPrivateKey(private_key); } }; ...}}setInsecure() 的实现可以从 websockets::network::SecuredEsp8266TcpClient 中获取:
namespace websockets { namespace network { typedef GenericEspTcpClient<WiFiClient> Esp8266TcpClient;
class SecuredEsp8266TcpClient : public GenericEspTcpClient<WiFiClientSecure> { public: void setInsecure() { this->client.setInsecure(); } ... }}}最终的修改结果:
namespace websockets { namespace network { typedef GenericEspTcpClient<WiFiClient> Esp32TcpClient;
class SecuredEsp32TcpClient : public GenericEspTcpClient<WiFiClientSecure> { public: void setCACert(const char* ca_cert) { this->client.setCACert(ca_cert); }
void setCertificate(const char* client_ca) { this->client.setCertificate(client_ca); }
void setPrivateKey(const char* private_key) { this->client.setPrivateKey(private_key); }
void setInsecure() { this->client.setInsecure(); } }; ...}} ESP32 WebsocketsClient连接wss协议的服务器
https://fuwari.vercel.app/posts/嵌入式/esp/esp32-websocketsclient连接wss协议的服务器/