【问题标题】:Can't connect ESP32 to websocket server deployed to Heroku无法将 ESP32 连接到部署到 Heroku 的 websocket 服务器
【发布时间】:2021-05-02 00:32:38
【问题描述】:

这是我的 ESP32 代码,

#include <WiFi.h>
#include <WebSocketClient.h>
#include <ArduinoJson.h> 
const char* ssid     = "###";
const char* password = "###";
 
char path[] = "/";
char host[] = "https://hidden-thicket-03510.herokuapp.com";
 
WebSocketClient webSocketClient;
WiFiClient client;

int timer=0;
void connnect(){
   if (client.connect(host,443)) {
    Serial.println("Connected");
  } else {
    Serial.println("Connection failed.");
  }
 
  webSocketClient.path = path;
  webSocketClient.host = host;
  if (webSocketClient.handshake(client)) {
    Serial.println("Handshake successful");
  } else {
    Serial.println("Handshake failed.");
  }
}
void setup() {
  Serial.begin(115200);
 
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
 
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
 
  delay(5000);
 
 connnect();

 if (client.connected()) {
   webSocketClient.sendData("Info to be echoed back");
 }
 
}
 
void loop() {
  String data;
  
    if (client.connected()) {

    webSocketClient.getData(data);
    Serial.println(data);
    int data_len = data.length() + 1; 
    char char_array[data_len];
    data.toCharArray(char_array, data_len);
    StaticJsonDocument<1200> doc;

    DeserializationError err=deserializeJson(doc,char_array);

    const char* a=doc["message"];
    
    if (data_len > 1) {
      Serial.print("Received data: ");
      Serial.println(a);
    }
    
  } else {
    Serial.println("Client disconnected.");
    connnect();
  }
 
  delay(3000);
 
}

这是在 Heroku 上运行的服务器代码

var WebSocketServer = require('websocket').server;
var http = require('http');

var server = http.createServer(function(request, response) {
    console.log((new Date()) + ' Received request for ' + request.url);
    response.writeHead(404);
    response.end();
});
let port =process.env.PORT || 5000;
server.listen(port, function() {
    console.log((new Date()) + ' Server is listening on port 5000');
});

wsServer = new WebSocketServer({
    httpServer: server
});
const clients={}
wsServer.on('request', request=> { 
    var connection = request.accept(null, request.origin);
    console.log((new Date()) + ' Connection accepted.');
    
    const clientId=guid();
    clients[clientId]={
        "connection":connection
    };

    // connection.sendUTF("JSON.stringify(payload)")
    connection.on('open',()=>{console.log("opened")})

    connection.on('message', message => {
        console.log(message);
        var a=JSON.stringify({'message':'sdaed'})
        connection.send(a)
        
    });

    connection.on('close', (reasonCode, description) =>{
        console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
    });

    const payload={
        "method":"connect",
        "clientId":clientId
    }
    
    
});



const guid=()=> {
    const s4=()=> Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);     
    return `${s4() + s4()}-${s4()}-${s4()}-${s4()}-${s4() + s4() + s4()}`;
  }


当我在我的 PC 上本地运行服务器时,ESP32 连接到服务器。但是当我将我的服务器部署到 Heroku 并尝试连接 ESP32 握手失败时发生。这是我得到的串行监视器上的输出

Connected
Waiting...
Waiting...
Waiting...
Handshake failed.
Client disconnected.
Connected
Waiting...
Waiting...
Waiting...
Handshake failed.
Client disconnected.
Connected
Waiting...
Waiting...
Waiting...
Waiting...
Waiting...
Handshake failed.

部署到服务器没有问题,因为当我使用 nodejs websocket 客户端(来自 repo 的示例)时,它成功连接到部署的 Heroku 服务器。我尝试将端口号更改为 80 并在 Arduino 脚本上使用“http://hidden-thicket-03510.herokuapp.com”,但它仍然不起作用。

为什么我的 ESP32 可以连接到本地运行的服务器,但部署到服务器时却无法连接

P.S - 如果你想测试一下,上面的服务器仍然可以工作。

任何帮助将不胜感激!

【问题讨论】:

    标签: node.js http heroku websocket esp32


    【解决方案1】:

    这是因为您正在连接到 TLS 端点,但 WiFiClient 类(用于创建底层连接)没有实现 TLS。 WebSocketClient 类期望接收一个工作数据管道,但它却获得了一个必须设置 TLS 的 TCP 连接。

    Espressif 提供了 TCP+TLS 实现 WiFiClientSecure,因此请使用它来代替 WiFiClient。

    请注意,与各种桌面操作系统和浏览器不同,ESP 默认不包含任何根证书。因此它无法验证远程服务器并将拒绝连接。您必须手动将服务器的证书添加到您的 ESP32 项目中——CA、中间或叶子(CA 可能是最佳选择)。有关如何执行此操作的文档位于项目的 README 中。

    要获取与您的服务器关联的证书,我使用openssl

    openssl s_client -showcerts -connect hidden-thicket-03510.herokuapp.com:443
    

    我看到您的 CA 证书可能是名为“DigiCert High Assurance EV Root CA”的证书。复制输出中的最后一个 PEM 块(base64 以 -----BEGIN CERTIFICATE----- 开头并以 -----END CERTIFICATE----- 结尾,包括在内),将其粘贴到文件“ca.pem”并按照说明将其添加到您的 ESP 项目中。

    要验证此文件是否为 CA 证书,请运行

    openssl x509 -in ca.pem -text -noout
    

    输出应包括Subject: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert High Assurance EV Root CA

    【讨论】:

    • 我会检查一下看看。谢谢你的回答
    • 我对此有一些问题,我已将其作为问题发布。你能看一下吗。链接是stackoverflow.com/questions/65942740/…
    • 你能解释一下“以.....开头的base 64”是什么意思吗?谢谢
    • 就是这样的东西。它是二进制数据,base64 编码可表示为文本。 MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
    猜你喜欢
    • 2021-10-18
    • 1970-01-01
    • 2012-05-26
    • 2020-07-04
    • 2017-08-02
    • 1970-01-01
    • 1970-01-01
    • 2013-09-07
    • 1970-01-01
    相关资源
    最近更新 更多