当前位置:   article > 正文

c++ websocket客户端_ESP32 Arduino教程:Websocket客户端

esp32 arduino websocket client

介绍

本文旨在介绍如何在使用Arduino内核的ESP32上创建一个简单的websocket客户端。我们将用它来联系一个远程测试websocket服务器。本ESP32教程的测试是使用集成在ESP32开发板中的DFRobot的ESP-WROOM-32设备进行的。

安装库文件

为了不必关注websocket协议的底层细节,我们将使用一个辅助库文件来帮助我们处理这些细节。

您可以点击此处查看库文件的GitHub页面。请注意,这是一个ESP8266库文件,在撰写本文时,ESP32还没有官方支持的库文件。尽管如此,通过一些更改,我们可以在ESP32上运行此库文件。

遗憾的是,Arduino IDE库管理器尚不提供此库文件。因此,我们需要手动安装。

为此,我们需要下载源代码,单击GitHub页面顶部“Clone or download(拷贝或下载)”按钮,然后单击“Download ZIP(下载压缩文件)”按钮即可获得源代码。图1中突出显示了这些按钮。

113884d5b270e96a6a0eefaab7616554.png

图1 - 从GitHub上下载库文件

在下载的“.zip”文件中有一个名为ESP8266-Websocket-master的文件夹。将此文件夹解压并重命名为ESP8266-Websocket。

现在,我们需要手动将解压和重命名的文件夹放在其他Arduino库文件的同一目录中。通常而言,这些库文件位于Windows用户文档(Documents)中名为Arduino的文件夹中。例如,在此示例中,库文件的存储地址为C: Users MyUsername Documents Arduino libraries。

在找到Arduino库文件夹后,只需将ESP8266-Websocket文件夹粘贴到其中即可。

在继续编程之前,我们需要更改ESP8266-Websocket文件夹中某些函数文件的名称。如果未执行这些更改,那么在尝试编译ESP32的代码时,我们将收到函数名称冲突导致的相关错误。

因此,为了避免该错误,我们需要接受ESP32论坛帖子中的一些建议。按照这些建议,我们需要打开ESP8266-Websocket文件夹中的MD5.c和MD5.h文件并重命名以下函数:

将MD5Init更改为MD5InitXXX

将MD5Update更改为MD5UpdateXXX

将MD5Final更改为MD5FinalXXX

请注意,函数名末尾的后缀XXX可以是其他内容,只要不使用原始名称就可以,使用原始名称会与其他定义相冲突。但无论怎样命名,我们都必须在.c和.h的文件中使用相同的新名称。

最后,保存更改并打开Arduino IDE,我们应该能够从该库中找到示例,如图2所示。

d926aa54c77c1c823ce314921d41245c.png

图2 - Arduino IDE上可用的库文件示例

接下来我们将分析以下代码,这些基于WebSocletClient_Demo的代码用于通过ESP32与服务器建立连接,我强烈建议您仔细了解一下WebSocletClient_Demo。其使用示例也可以从此处的GitHub页面获得。

全局变量和引用文件

我们将从导入一些库文件开始编写代码。首先,我们需要WiFi.h库文件,它用于连接WiFi网络。此外,我们还需要引用WebSocketClient.h库文件,以便可以访问连接服务器所需的所有函数。

#include #include 

接下来,我们将把连接WiFi网络所需的证书放入两个全局变量。网络名称(ssid)和密码是必需的信息。

const char* ssid = "YourNetworkName";const char* password = "YourNetworkPassword;

随后,我们需要指定连接的主机以及使用的URL路径。为简单起见,我们将使用在线回显 websocket服务器,它可以返回我们先前发送的内容。这样我们就可以测试我们的客户端,而无需自己设置websocket服务器。

因此,我们可将服务器主机设置为demos.kaazing.com,URL路径设置为/ echo。您可以点击此处测试此服务器。

char path[] = "/echo";char host[] = "demos.kaazing.com";

我们还需要一个WebSocketClient类对象,用于调用与服务器交互所需的函数。最后,我们需要一个WiFiClient类对象,用于在后台为WebSocketClient对象提供支持。

WebSocketClient webSocketClient;WiFiClient client;

setup函数

现在,我们将使用Arduino setup函数执行初始化任务。按照惯例,我们将首先建立一个串口连接以输出程序的结果。接下来,我们将把ESP32连接到一个WiFi网络。关于如何建立网络连接的详细信息,请参考先前的教程内容。

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);

在连接WiFi网络之后,我们将通过调用WiFiClient对象的connect方法与主机建立TCP连接。

此方法的第一个参数是一个字符串,它表示我们尝试访问的主机(我们在先前已将其声明为全局变量),第二个参数是正在侦听的端口编号。我们使用的测试服务器正在侦听端口80,即默认的HTTP端口。

我们还引用了对此连接尝试的错误检查程序。如果连接失败,程序将向串行端口打印一条消息,但程序仍将继续运行并最终失败。我们这样做是为了简化测试过程,因为我们处于受控的测试环境中。对于在实际应用中使用的弹性程序,我们应该引用更强大的错误检查程序,并在检测到错误时采取相应的措施。

if(client.connect(host, 80)) { Serial.println("Connected");}else { Serial.println("Connection failed.");}

接下来我们需要执行websocket handshake握手。可通过调用之前声明的WebSocketClient对象的handshake方法来完成握手。此方法的输入参数为WiFiClient对象,利用该对象与服务器通信。

如需了解更多关于握手期间的细节信息,可以点击此处查看源代码。重要的是,它将向服务器发送HTTP请求以升级websocket连接。

此升级很有必要,这是因为服务器可以利用websocket协议通过相同的端口与HTTP和websocket客户端进行通信[1]。因此,客户端需要指定通信对象为websocket。

在调用handshake方法之前,我们需要为WebSocketClient的路径和主机数据分配全局变量,这些先前定义的全局变量可用于表示主机及URL路径。

webSocketClient.path = path;webSocketClient.host = host;if (webSocketClient.handshake(client)) { Serial.println("Handshake successful");} else { Serial.println("Handshake failed.");}

完整的setup函数如下所示。

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); if (client.connect(host, 80)) { 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."); }}

主循环

让我们开始编写主循环程序。现在,我们将编写程序向服务器发送和接收数据。首先,我们需要声明一个String类型的变量,该变量将用作从服务器接收的内容的数据缓冲区。

String data;

接下来,我们将检查客户端与服务器是否仍然处于连接状态。我们之前使用WiFiClient对象连接了服务器。 因此,我们将通过调用其connected方法检查连接状态是否正常,该方法不带参数,如果连接仍处于活动状态,则返回true,否则返回false。

在初始化WebSocketClient之后使用WiFiClient对象似乎很奇怪。我们可以将WebSocketClient视为WiFiClient上层的封装包,用于处理websocket协议的特定任务。因此,检查连接是否仍然可用是较低层级的函数,所以我们可以直接使用WiFiClient对象。

如果客户端与服务器仍然处于活跃状态,我们将向其发送一些数据。为此,我们只需调用WebSocketClient对象的sendData方法,将包含发送内容的字符串作为其输入参数。此函数的返回值为空(void)。

webSocketClient.sendData("Info to be echoed back");

如前所述,我们访问的服务器将简单地回显我们发送给它的数据。因此,我们可以从客户端获取数据,它应该与我们之前发送的内容完全匹配。

为了从服务器获取数据,我们调用了getData函数,将字符串缓冲区作为其输入参数,服务器的返回内容将被存放在此字符串缓冲区中。

webSocketClient.getData(data);

随后,如果返回内容的长度大于0,我们可以简单地打印出接收的数据。完整的主循环函数如下所示,其中包含了打印内容。请注意,在每次迭代主循环函数之前,我们还添加了一个小小的延迟。

void loop() { String data; if (client.connected()) { webSocketClient.sendData("Info to be echoed back"); webSocketClient.getData(data); if (data.length() > 0) { Serial.print("Received data: "); Serial.println(data); } } else { Serial.println("Client disconnected."); } delay(3000);}

最终代码

最终源代码如下所示。

#include #include const char* ssid = "YourNetworkName";const char* password = "YourNetworkPassword;char path[] = "/echo";char host[] = "demos.kaazing.com";WebSocketClient webSocketClient;WiFiClient client;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); if (client.connect(host, 80)) { 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 loop() { String data; if (client.connected()) { webSocketClient.sendData("Info to be echoed back"); webSocketClient.getData(data); if (data.length() > 0) { Serial.print("Received data: "); Serial.println(data); } } else { Serial.println("Client disconnected."); } delay(3000);}

测试代码

为了测试此代码,只需编译并将其上传到ESP32即可。您将得到类似于图1的输出结果,发送至服务器的消息被返回并打印至串口控制台。

请注意,如果未按照“安装库文件”的说明重命名库函数,则无法编译ESP32代码。

e5c33d04cd619254fd66089b90b2075a.png

图3 - 程序的输出结果

注:本文作者是Nuno Santos,他是一位和蔼可亲的电子和计算机工程师,住在葡萄牙里斯本 (Lisbon)。

他写了200多篇有关ESP32、ESP8266的有用的教程和项目。

ESP32教程大全: http://mc.dfrobot.com.cn/thread-271930-1-1.html

ESP32 tutorial:https://www.dfrobot.com/blog-964.html

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

闽ICP备14008679号