STM32 WebSocket 实现
介绍
WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,广泛用于需要实时数据传输的应用场景,如聊天应用、实时游戏和 IoT 设备通信。在 STM32 微控制器上实现 WebSocket 协议,可以帮助你构建高效的实时通信系统。
本文将逐步讲解如何在 STM32 上实现 WebSocket 协议,并通过实际案例展示其应用。
WebSocket 协议简介
WebSocket 协议允许客户端和服务器之间进行双向通信。与传统的 HTTP 请求-响应模式不同,WebSocket 在建立连接后,客户端和服务器可以随时发送数据,而无需等待对方的请求。
WebSocket 协议的握手过程基于 HTTP,握手成功后,通信双方将切换到 WebSocket 协议进行数据传输。
STM32 上的 WebSocket 实现
在 STM32 上实现 WebSocket 协议,通常需要以下步骤:
- 建立 TCP 连接:WebSocket 协议基于 TCP,因此首先需要建立一个 TCP 连接。
- 进行 WebSocket 握手:客户端发送一个 HTTP 请求,服务器响应并确认握手。
- 数据传输:握手成功后,客户端和服务器可以通过 WebSocket 协议进行数据传输。
1. 建立 TCP 连接
在 STM32 上,可以使用 LwIP(轻量级 IP 协议栈)来建立 TCP 连接。以下是一个简单的 TCP 客户端示例:
#include "lwip/tcp.h"
struct tcp_pcb *pcb;
void tcp_connect() {
pcb = tcp_new();
if (pcb != NULL) {
ip_addr_t server_ip;
IP4_ADDR(&server_ip, 192, 168, 1, 100); // 服务器 IP 地址
tcp_connect(pcb, &server_ip, 8080, tcp_connected_callback);
}
}
err_t tcp_connected_callback(void *arg, struct tcp_pcb *tpcb, err_t err) {
if (err == ERR_OK) {
// TCP 连接成功
tcp_send(tpcb, "Hello Server", 12);
}
return ERR_OK;
}
2. 进行 WebSocket 握手
WebSocket 握手是一个 HTTP 请求-响应过程。客户端发送一个包含特定头部的 HTTP 请求,服务器响应并确认握手。
以下是一个简单的 WebSocket 握手请求示例:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
服务器响应如下:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
在 STM32 上,可以通过 LwIP 发送和接收 HTTP 数据包来实现握手。
3. 数据传输
握手成功后,客户端和服务器可以通过 WebSocket 协议进行数据传输。WebSocket 数据帧的格式如下:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
| |Masking-key, if MASK set to 1 |
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------- - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Payload Data continued ... |
+---------------------------------------------------------------+
在 STM32 上,可以通过解析和构造 WebSocket 数据帧来实现数据传输。
实际案例:STM32 WebSocket 聊天应用
假设我们要实现一个简单的 STM32 WebSocket 聊天应用。STM32 作为客户端,连接到 WebSocket 服务器,并实时接收和发送消息。
1. 建立 TCP 连接
首先,STM32 需要与 WebSocket 服务器建立 TCP 连接:
void tcp_connect() {
pcb = tcp_new();
if (pcb != NULL) {
ip_addr_t server_ip;
IP4_ADDR(&server_ip, 192, 168, 1, 100); // 服务器 IP 地址
tcp_connect(pcb, &server_ip, 8080, tcp_connected_callback);
}
}
2. 进行 WebSocket 握手
建立 TCP 连接后,STM32 发送 WebSocket 握手请求:
void send_websocket_handshake() {
char handshake_request[] = "GET /chat HTTP/1.1\r\n"
"Host: server.example.com\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
"Sec-WebSocket-Version: 13\r\n\r\n";
tcp_write(pcb, handshake_request, strlen(handshake_request), TCP_WRITE_FLAG_COPY);
tcp_output(pcb);
}
3. 数据传输
握手成功后,STM32 可以接收和发送 WebSocket 数据帧。以下是一个简单的数据接收和发送示例:
void websocket_receive_data(struct tcp_pcb *tpcb, struct pbuf *p) {
// 解析 WebSocket 数据帧
uint8_t *data = (uint8_t *)p->payload;
uint8_t opcode = data[0] & 0x0F;
uint8_t mask = (data[1] >> 7) & 0x01;
uint64_t payload_len = data[1] & 0x7F;
if (payload_len == 126) {
payload_len = (data[2] << 8) | data[3];
} else if (payload_len == 127) {
payload_len = ((uint64_t)data[2] << 56) | ((uint64_t)data[3] << 48) |
((uint64_t)data[4] << 40) | ((uint64_t)data[5] << 32) |
((uint64_t)data[6] << 24) | ((uint64_t)data[7] << 16) |
((uint64_t)data[8] << 8) | data[9];
}
// 处理接收到的数据
if (opcode == 0x01) { // 文本帧
char message[payload_len + 1];
memcpy(message, data + 2, payload_len);
message[payload_len] = '\0';
printf("Received message: %s\n", message);
}
// 发送响应消息
char response[] = "Hello from STM32";
tcp_write(tpcb, response, strlen(response), TCP_WRITE_FLAG_COPY);
tcp_output(tpcb);
}
总结
通过本文的学习,你应该已经掌握了如何在 STM32 上实现 WebSocket 协议。WebSocket 协议在实时通信应用中具有广泛的应用前景,掌握这一技术将有助于你构建高效的 IoT 设备和实时通信系统。
附加资源
练习
- 尝试在 STM32 上实现一个 WebSocket 服务器,并与其他客户端进行通信。
- 修改上述代码,使其支持二进制数据的传输。
- 研究 WebSocket 协议的安全性,并尝试在 STM32 上实现 WebSocket over TLS(WSS)。