编译环境是VS+PIO,调用的库是ArduinoWebsockets.h,这个在Libraries里有哈,直接搜索下载即可。
最近有个项目客户服务器是Websocket server,走的是WSS协议,要加密的嘛,我这边用ESP8266连上秒过,ESP32一直连不上,提示
然后就是愉快地找底层,把ESP8266和ESP32一步一步对比,终于发现了问题所在:
原因就是ESP8266和ESP32都没有证书的,那么当客户端的话正常流程就是跳过证书验证就好了,结果ESP8266跳过去了,ESP32没跳过去。
那好,加个函数就行了,下面附上代码:
main.cpp:
#include #include #includeconst char* ssid = "your_ssid"; //Enter SSID const char* password = "your_pswd"; //Enter Password const char* websockets_server_host = "your_host"; //Enter server adress const uint16_t websockets_server_port = 8080; // Enter server port 我这里端口号是自动判断的 using namespace websockets; void onMessageCallback(WebsocketsMessage message) { Serial.print("Got Message: "); Serial.println(message.data()); } void onEventsCallback(WebsocketsEvent event, String data) { if(event == WebsocketsEvent::ConnectionOpened) { Serial.println("Connnection Opened"); } else if(event == WebsocketsEvent::ConnectionClosed) { Serial.println("Connnection Closed"); } else if(event == WebsocketsEvent::GotPing) { Serial.println("Got a Ping!"); } else if(event == WebsocketsEvent::GotPong) { Serial.println("Got a Pong!"); } } WebsocketsClient client; void setup() { Serial.begin(115200); // Connect to wifi WiFi.begin(ssid, password); // Wait some time to connect to wifi for(int i = 0; i < 10 && WiFi.status() != WL_CONNECTED; i++) { Serial.print("."); delay(1000); } Serial.print("ESP Ready! Use 'http://"); Serial.println(WiFi.localIP()); // run callback when messages are received client.onMessage(onMessageCallback); // run callback when events are occuring client.onEvent(onEventsCallback); // Connect to server client.connect(websockets_server_host); //注意这里只给了host一个参数,没有给端口号 // Send a message client.send("HELLO"); // Send a ping client.ping(); } void loop() { client.poll(); }
然后从connect()函数 用F12跳过去,然后找到对于WSS和HTTPS有特有的upgradeToSecuredConnection()函数,从这个函数跳进去,原本的代码是这样的:
//这个函数在ArduinoWebsocketsrcwebsockets_client.cpp 下
void WebsocketsClient::upgradeToSecuredConnection() {
#ifndef _WS_CONFIG_NO_SSL
auto client = new WSDefaultSecuredTcpClient;
#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
this->_client = std::shared_ptr(client);
this->_endpoint.setInternalSocket(this->_client);
#endif //_WS_CONFIG_NO_SSL
}
注意#define ESP8266或是#define ESP32无需用户自己定义。
实际上这几个if里判断的寄存器,例如_optional_ssl_ca_cert等,都是赋值了false的,因此这几个判断都不会进,那也就是说ESP8266比ESP32多进了一个 client->setInsecure();
这里就是关键点,我们需要让ESP32也进一次client->setInsecure() 函数,因此我们把这段代码改成:
//这个函数在ArduinoWebsocketsrcwebsockets_client.cpp 下
void WebsocketsClient::upgradeToSecuredConnection() {
#ifndef _WS_CONFIG_NO_SSL
auto client = new WSDefaultSecuredTcpClient;
#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
|| 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
this->_client = std::shared_ptr(client);
this->_endpoint.setInternalSocket(this->_client);
#endif //_WS_CONFIG_NO_SSL
}
但是ESP32里client->setInsecure()函数会报错,这是因为对于ESP32的client成员并没有setInsecure();函数,因此我们给他手动添加一个,
首先可以知道在这个函数里client成员是auto client = new WSDefaultSecuredTcpClient;这一句定义的,因此我们直接对WSDefaultSecuredTcpClient 转到定义,然后:
#ifdef ESP8266
#define PLATFORM_DOES_NOT_SUPPORT_BLOCKING_READ
#include
#define WSDefaultTcpClient websockets::network::Esp8266TcpClient
#define WSDefaultTcpServer websockets::network::Esp8266TcpServer
#ifndef _WS_CONFIG_NO_SSL
// OpenSSL Dependent
#define WSDefaultSecuredTcpClient websockets::network::SecuredEsp8266TcpClient //先从这里的“SecuredEsp8266TcpClient”跳进去,复制好setInsecure()函数后,看下面注释
#endif //_WS_CONFIG_NO_SSL
#elif defined(ESP32)
#define PLATFORM_DOES_NOT_SUPPORT_BLOCKING_READ
#include
#define WSDefaultTcpClient websockets::network::Esp32TcpClient
#define WSDefaultTcpServer websockets::network::Esp32TcpServer
#ifndef _WS_CONFIG_NO_SSL
// OpenSSL Dependent
#define WSDefaultSecuredTcpClient websockets::network::SecuredEsp32TcpClient //复制好ESP8266那边定义的setInsecure()函数后,在从这里的“SecuredEsp32TcpClient”跳进去
#endif //_WS_CONFIG_NO_SSL
#elif defined(ARDUINO_TEENSY41)
#define PLATFORM_DOES_NOT_SUPPORT_BLOCKING_READ
#define _WS_CONFIG_NO_SSL
#include
#include
#define WSDefaultTcpClient websockets::network::Teensy41TcpClient
#define WSDefaultTcpServer websockets::network::Teensy41TcpServer
#endif
从SecuredEsp32TcpClient跳进来之后把刚刚ESP8266那边的setInsecure()函数复制进来,代码变成这样:
//这段代码在ArduinoWebsocketssrctiny_websocketsnetworkesp32esp32_tcp.hpp下 class SecuredEsp32TcpClient : public GenericEspTcpClient{ 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(); } };
这样子就对SecuredEsp32TcpClient 成员添加了setInsecure()函数。
setInsecure()函数实际上是设置了WIFI库里的部分寄存器,如下:
void WiFiClientSecure::setInsecure()
{
_CA_cert = NULL;
_cert = NULL;
_private_key = NULL;
_pskIdent = NULL;
_psKey = NULL;
_use_insecure = true;
}
很庆幸这几个寄存器不但用于ESP8266,而且也用于ESP32,并且功能都一样,因此我们只需要调用一遍这个函数即可解决“ESP32不能像ESP8266那样连上wss的websocket服务器”这个问题。



