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协议的服务器/
作者
Asuwee
发布于
2025-10-23
许可协议
CC BY-NC-SA 4.0