赞
踩
编译环境是VS+PIO,调用的库是ArduinoWebsockets.h,这个在Libraries里有哈,直接搜索下载即可。
最近有个项目客户服务器是Websocket server,走的是WSS协议,要加密的嘛,我这边用ESP8266连上秒过,ESP32一直连不上,提示
然后就是愉快地找底层,把ESP8266和ESP32一步一步对比,终于发现了问题所在:
原因就是ESP8266和ESP32都没有证书的,那么当客户端的话正常流程就是跳过证书验证就好了,结果ESP8266跳过去了,ESP32没跳过去。
那好,加个函数就行了,下面附上代码:
main.cpp:
- #include <Arduino.h>
-
- #include <ArduinoWebsockets.h>
- #include <WiFi.h>
-
- const 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()函数,从这个函数跳进去,原本的代码是这样的:
- //这个函数在ArduinoWebsocket\src\websockets_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<WSDefaultSecuredTcpClient>(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() 函数,因此我们把这段代码改成:
- //这个函数在ArduinoWebsocket\src\websockets_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<WSDefaultSecuredTcpClient>(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 <tiny_websockets/network/esp8266/esp8266_tcp.hpp>
- #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 <tiny_websockets/network/esp32/esp32_tcp.hpp>
- #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 <tiny_websockets/network/teensy41/teensy41_tcp_client.hpp>
- #include <tiny_websockets/network/teensy41/teensy41_tcp_server.hpp>
-
- #define WSDefaultTcpClient websockets::network::Teensy41TcpClient
- #define WSDefaultTcpServer websockets::network::Teensy41TcpServer
- #endif
从SecuredEsp32TcpClient跳进来之后把刚刚ESP8266那边的setInsecure()函数复制进来,代码变成这样:
- //这段代码在ArduinoWebsockets\src\tiny_websockets\network\esp32\esp32_tcp.hpp下
- 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();
- }
- };
这样子就对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服务器”这个问题。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。