当前位置:   article > 正文

Arduino ESP32做Websocket client 连接WSS协议的服务器_websocketsclient.h

websocketsclient.h

编译环境是VS+PIO,调用的库是ArduinoWebsockets.h,这个在Libraries里有哈,直接搜索下载即可。

最近有个项目客户服务器是Websocket server,走的是WSS协议,要加密的嘛,我这边用ESP8266连上秒过,ESP32一直连不上,提示

 然后就是愉快地找底层,把ESP8266和ESP32一步一步对比,终于发现了问题所在:

原因就是ESP8266和ESP32都没有证书的,那么当客户端的话正常流程就是跳过证书验证就好了,结果ESP8266跳过去了,ESP32没跳过去。

那好,加个函数就行了,下面附上代码:

main.cpp:

  1. #include <Arduino.h>
  2. #include <ArduinoWebsockets.h>
  3. #include <WiFi.h>
  4. const char* ssid = "your_ssid"; //Enter SSID
  5. const char* password = "your_pswd"; //Enter Password
  6. const char* websockets_server_host = "your_host"; //Enter server adress
  7. const uint16_t websockets_server_port = 8080; // Enter server port 我这里端口号是自动判断的
  8. using namespace websockets;
  9. void onMessageCallback(WebsocketsMessage message) {
  10. Serial.print("Got Message: ");
  11. Serial.println(message.data());
  12. }
  13. void onEventsCallback(WebsocketsEvent event, String data) {
  14. if(event == WebsocketsEvent::ConnectionOpened) {
  15. Serial.println("Connnection Opened");
  16. } else if(event == WebsocketsEvent::ConnectionClosed) {
  17. Serial.println("Connnection Closed");
  18. } else if(event == WebsocketsEvent::GotPing) {
  19. Serial.println("Got a Ping!");
  20. } else if(event == WebsocketsEvent::GotPong) {
  21. Serial.println("Got a Pong!");
  22. }
  23. }
  24. WebsocketsClient client;
  25. void setup() {
  26. Serial.begin(115200);
  27. // Connect to wifi
  28. WiFi.begin(ssid, password);
  29. // Wait some time to connect to wifi
  30. for(int i = 0; i < 10 && WiFi.status() != WL_CONNECTED; i++) {
  31. Serial.print(".");
  32. delay(1000);
  33. }
  34. Serial.print("ESP Ready! Use 'http://");
  35. Serial.println(WiFi.localIP());
  36. // run callback when messages are received
  37. client.onMessage(onMessageCallback);
  38. // run callback when events are occuring
  39. client.onEvent(onEventsCallback);
  40. // Connect to server
  41. client.connect(websockets_server_host); //注意这里只给了host一个参数,没有给端口号
  42. // Send a message
  43. client.send("HELLO");
  44. // Send a ping
  45. client.ping();
  46. }
  47. void loop() {
  48. client.poll();
  49. }

然后从connect()函数 用F12跳过去,然后找到对于WSS和HTTPS有特有的upgradeToSecuredConnection()函数,从这个函数跳进去,原本的代码是这样的:

  1. //这个函数在ArduinoWebsocket\src\websockets_client.cpp 下
  2. void WebsocketsClient::upgradeToSecuredConnection() {
  3. #ifndef _WS_CONFIG_NO_SSL
  4. auto client = new WSDefaultSecuredTcpClient;
  5. #ifdef ESP8266
  6. if(
  7. this->_optional_ssl_fingerprint
  8. || (this->_optional_ssl_rsa_cert && this->_optional_ssl_rsa_private_key)
  9. || (this->_optional_ssl_ec_cert && this->_optional_ssl_ec_private_key)
  10. || this->_optional_ssl_trust_anchors
  11. || this->_optional_ssl_known_key
  12. ) {
  13. if(this->_optional_ssl_fingerprint) { //这个判断不会进
  14. client->setFingerprint(this->_optional_ssl_fingerprint);
  15. }
  16. if(this->_optional_ssl_trust_anchors) { //这个判断不会进
  17. client->setTrustAnchors(this->_optional_ssl_trust_anchors);
  18. }
  19. if(this->_optional_ssl_known_key) { //这个判断不会进
  20. client->setKnownKey(this->_optional_ssl_known_key);
  21. }
  22. if(this->_optional_ssl_rsa_cert && this->_optional_ssl_rsa_private_key) { //这个判断不会进
  23. client->setClientRSACert(this->_optional_ssl_rsa_cert, this->_optional_ssl_rsa_private_key);
  24. }
  25. if(this->_optional_ssl_ec_cert && this->_optional_ssl_ec_private_key) { //这个判断不会进
  26. client->setClientECCert(this->_optional_ssl_ec_cert, this->_optional_ssl_ec_private_key);
  27. }
  28. } else { //这个判断会进
  29. client->setInsecure();
  30. }
  31. #elif defined(ESP32)
  32. if(this->_optional_ssl_ca_cert) { //这个判断不会进
  33. client->setCACert(this->_optional_ssl_ca_cert);
  34. }
  35. if(this->_optional_ssl_client_ca) { //这个判断不会进
  36. client->setCertificate(this->_optional_ssl_client_ca);
  37. }
  38. if(this->_optional_ssl_private_key) { //这个判断不会进
  39. client->setPrivateKey(this->_optional_ssl_private_key);
  40. }
  41. #endif
  42. this->_client = std::shared_ptr<WSDefaultSecuredTcpClient>(client);
  43. this->_endpoint.setInternalSocket(this->_client);
  44. #endif //_WS_CONFIG_NO_SSL
  45. }

注意#define ESP8266或是#define ESP32无需用户自己定义。

        实际上这几个if里判断的寄存器,例如_optional_ssl_ca_cert等,都是赋值了false的,因此这几个判断都不会进,那也就是说ESP8266比ESP32多进了一个 client->setInsecure();

        这里就是关键点,我们需要让ESP32也进一次client->setInsecure() 函数,因此我们把这段代码改成:

  1. //这个函数在ArduinoWebsocket\src\websockets_client.cpp 下
  2. void WebsocketsClient::upgradeToSecuredConnection() {
  3. #ifndef _WS_CONFIG_NO_SSL
  4. auto client = new WSDefaultSecuredTcpClient;
  5. #ifdef ESP8266
  6. if(
  7. this->_optional_ssl_fingerprint
  8. || (this->_optional_ssl_rsa_cert && this->_optional_ssl_rsa_private_key)
  9. || (this->_optional_ssl_ec_cert && this->_optional_ssl_ec_private_key)
  10. || this->_optional_ssl_trust_anchors
  11. || this->_optional_ssl_known_key
  12. ) {
  13. if(this->_optional_ssl_fingerprint) { //这个判断不会进
  14. client->setFingerprint(this->_optional_ssl_fingerprint);
  15. }
  16. if(this->_optional_ssl_trust_anchors) { //这个判断不会进
  17. client->setTrustAnchors(this->_optional_ssl_trust_anchors);
  18. }
  19. if(this->_optional_ssl_known_key) { //这个判断不会进
  20. client->setKnownKey(this->_optional_ssl_known_key);
  21. }
  22. if(this->_optional_ssl_rsa_cert && this->_optional_ssl_rsa_private_key) { //这个判断不会进
  23. client->setClientRSACert(this->_optional_ssl_rsa_cert, this->_optional_ssl_rsa_private_key);
  24. }
  25. if(this->_optional_ssl_ec_cert && this->_optional_ssl_ec_private_key) { //这个判断不会进
  26. client->setClientECCert(this->_optional_ssl_ec_cert, this->_optional_ssl_ec_private_key);
  27. }
  28. } else { //这个判断会进!
  29. client->setInsecure();
  30. }
  31. #elif defined(ESP32)
  32. if(
  33. this->_optional_ssl_ca_cert
  34. || this->_optional_ssl_client_ca
  35. || this->_optional_ssl_private_key
  36. ) {
  37. if(this->_optional_ssl_ca_cert) { //这个判断不会进
  38. client->setCACert(this->_optional_ssl_ca_cert);
  39. }
  40. if(this->_optional_ssl_client_ca) { //这个判断不会进
  41. client->setCertificate(this->_optional_ssl_client_ca);
  42. }
  43. if(this->_optional_ssl_private_key) { //这个判断不会进
  44. client->setPrivateKey(this->_optional_ssl_private_key);
  45. }
  46. }
  47. else client->setInsecure();
  48. #endif
  49. this->_client = std::shared_ptr<WSDefaultSecuredTcpClient>(client);
  50. this->_endpoint.setInternalSocket(this->_client);
  51. #endif //_WS_CONFIG_NO_SSL
  52. }

但是ESP32里client->setInsecure()函数会报错,这是因为对于ESP32的client成员并没有setInsecure();函数,因此我们给他手动添加一个,

首先可以知道在这个函数里client成员是auto client = new WSDefaultSecuredTcpClient;这一句定义的,因此我们直接对WSDefaultSecuredTcpClient 转到定义,然后:

  1. #ifdef ESP8266
  2. #define PLATFORM_DOES_NOT_SUPPORT_BLOCKING_READ
  3. #include <tiny_websockets/network/esp8266/esp8266_tcp.hpp>
  4. #define WSDefaultTcpClient websockets::network::Esp8266TcpClient
  5. #define WSDefaultTcpServer websockets::network::Esp8266TcpServer
  6. #ifndef _WS_CONFIG_NO_SSL
  7. // OpenSSL Dependent
  8. #define WSDefaultSecuredTcpClient websockets::network::SecuredEsp8266TcpClient //先从这里的“SecuredEsp8266TcpClient”跳进去,复制好setInsecure()函数后,看下面注释
  9. #endif //_WS_CONFIG_NO_SSL
  10. #elif defined(ESP32)
  11. #define PLATFORM_DOES_NOT_SUPPORT_BLOCKING_READ
  12. #include <tiny_websockets/network/esp32/esp32_tcp.hpp>
  13. #define WSDefaultTcpClient websockets::network::Esp32TcpClient
  14. #define WSDefaultTcpServer websockets::network::Esp32TcpServer
  15. #ifndef _WS_CONFIG_NO_SSL
  16. // OpenSSL Dependent
  17. #define WSDefaultSecuredTcpClient websockets::network::SecuredEsp32TcpClient //复制好ESP8266那边定义的setInsecure()函数后,在从这里的“SecuredEsp32TcpClient”跳进去
  18. #endif //_WS_CONFIG_NO_SSL
  19. #elif defined(ARDUINO_TEENSY41)
  20. #define PLATFORM_DOES_NOT_SUPPORT_BLOCKING_READ
  21. #define _WS_CONFIG_NO_SSL
  22. #include <tiny_websockets/network/teensy41/teensy41_tcp_client.hpp>
  23. #include <tiny_websockets/network/teensy41/teensy41_tcp_server.hpp>
  24. #define WSDefaultTcpClient websockets::network::Teensy41TcpClient
  25. #define WSDefaultTcpServer websockets::network::Teensy41TcpServer
  26. #endif

从SecuredEsp32TcpClient跳进来之后把刚刚ESP8266那边的setInsecure()函数复制进来,代码变成这样:

  1. //这段代码在ArduinoWebsockets\src\tiny_websockets\network\esp32\esp32_tcp.hpp下
  2. class SecuredEsp32TcpClient : public GenericEspTcpClient<WiFiClientSecure> {
  3. public:
  4. void setCACert(const char* ca_cert) {
  5. this->client.setCACert(ca_cert);
  6. }
  7. void setCertificate(const char* client_ca) {
  8. this->client.setCertificate(client_ca);
  9. }
  10. void setPrivateKey(const char* private_key) {
  11. this->client.setPrivateKey(private_key);
  12. }
  13. void setInsecure() { //这里修改了
  14. this->client.setInsecure();
  15. }
  16. };

这样子就对SecuredEsp32TcpClient 成员添加了setInsecure()函数。

setInsecure()函数实际上是设置了WIFI库里的部分寄存器,如下:

  1. void WiFiClientSecure::setInsecure()
  2. {
  3. _CA_cert = NULL;
  4. _cert = NULL;
  5. _private_key = NULL;
  6. _pskIdent = NULL;
  7. _psKey = NULL;
  8. _use_insecure = true;
  9. }

很庆幸这几个寄存器不但用于ESP8266,而且也用于ESP32,并且功能都一样,因此我们只需要调用一遍这个函数即可解决“ESP32不能像ESP8266那样连上wss的websocket服务器”这个问题。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/196386
推荐阅读
相关标签
  

闽ICP备14008679号