websocket - 通过 webscoket 连接 ESP8266 客户端(无库,只有 AT 命令)
问题描述
我正在使用 AT 命令在客户端实现 websocket。
我以此为基准并阅读了此内容。
硬件:ESP8266+arduino uno。
代码 :
String cmd = "AT+CIPSTART=\"TCP\",\""; cmd += SERVER_IP; cmd += "\",81"; //Start a TCP connection. to server SERVER_IP on port 81
if (!sendCommand(cmd, "OK", CONTINUE))
return;
delay(2000);
if (!sendCommand("AT+CIPSTATUS", "OK", CONTINUE))// Check for TCP Connection status.
return;
cmd = "GET 192.168.43.228:81 HTTP/1.1\r\n";
cmd += "Host: 192.168.43.228:81\r\n";
cmd += "Upgrade: websocket\r\n";
cmd += "Connection: Upgrade\r\n\r\n";
if (!sendCommand("AT+CIPSEND=" + String(cmd.length()), ">", CONTINUE)) {
sendCommand("AT+CIPCLOSE", "", CONTINUE);
Serial.println("Connection timeout.");
return;
}
sendCommand(cmd, "OK", CONTINUE);// Send data to server.
delay(1000);
readResponseData("");
登录 arduino 端:
ESP8266 Demo
AT+RST
OK
bBֆ@⸮Sc⸮⸮⸮ȤS⸮⸮⸮ɥ⸮⸮⸮⸮H⸮
[System Ready
, Vendo:⸮ݹ⸮⸮⸮ɹcom]
AT+GMR
0018000902
OK
AT+CWMODE?
+CWMODE:1
OK
AT+CWMODE=1
no change
AT+CWMODE=1
no change
AT+CIPMUX=0
OK
AT+CWJAP="AndroidAP","xxxx"
OK
Connected to WiFi.
AT+CWJAP="AndroidAP","xxxxx"
OK
AT+CWSAP=?
no this fun
AT+CIFSR
192.168.43.29
OK
Module is ready.
AT+CIPSTART="TCP","192.168.43.228",81
OK
Linked
AT+CIPSTATUS
STATUS:3
+CIPSTATUS:0,"TCP","192.168.43.228",81,0
OK
AT+CIPSEND=100
>
GET 192.168.43.228:81 HTTP/1.1
Host: 192.168.43.228:81
Upgradewrong syntax
ERROR
SEND OK
OK
Unlink
服务器端 :
WiFi connected
IP address:
192.168.43.228
Server available at ws://192.168.43.228:81
Accepted new web sockets client at index 0
--
...并且服务器没有任何其他内容,它应该在接受 websocket 后立即发送消息。
请给我一些见解:)
解决方案
我找到了一种解决方案。
事实上,我并不了解RFC4566的所有细节
成功握手后,您需要符合帧要求。它不仅仅是原始文本:)
对于有限的用例(即长度<125),这里是解决方案的概述:
char str[] = "Hello";
char buf[125];
bool toMask = true;
uint8_t extra = toMask ? 6 : 2;
buildFrame(str, buf, WS_OPCODE_TEXT, toMask);
ESP8266SendData(0, buf, str.length() + extra);
我已经对此进行了测试以获得:
void buildFrame(char *str, uint8_t *ret, uint8_t opcode, bool maskon) {
uint8_t mask[4];
int size = strlen(str);
// Opcode; final fragment
ret[0] = opcode | WS_FIN;
ret[1] = (uint8_t) (size) | (maskon == true ? WS_MASK : 0);
if (maskon) {
mask[0] = random(0, 256);
mask[1] = random(0, 256);
mask[2] = random(0, 256);
mask[3] = random(0, 256);
for (int i = 2; i < 4 + 2; ++i) {
ret[i] = mask[i - 2];
}
for (int i = 6; i < size + 6; i++) {
ret[i] = str[i - 6] ^ mask[(i - 6) % 4];
}
}
else {
for (int i = 2; i < size + 2; ++i) {
ret[i] = (uint8_t) str[i - 2];
}
}
}
对于帧解码:
uint8_t extractPayload(String buffer, String& payload) {
// here only payloads whose size < 125
bool FIN = buffer[0] & WS_FIN;
uint8_t opcode = buffer[0] & ~WS_FIN;
bool hasMask = buffer[1] & WS_MASK;
uint8_t len = buffer[1] & ~WS_MASK;
uint8_t mask[4];
if (hasMask) {
mask[0] = buffer[2];
mask[1] = buffer[3];
mask[2] = buffer[4];
mask[3] = buffer[5];
for (int i = 6; i < len + 6; i++) {
payload += (char) (buffer[i] ^ mask[(i - 6) % 4]);
}
}
else {
payload = buffer.substring(2);
}
Serial.print("FIN = "); Serial.println(FIN, HEX);
Serial.print("Opcode = "); Serial.println(opcode, HEX);
Serial.print("Mask = "); Serial.println(hasMask, HEX);
Serial.print("Payload length = "); Serial.println(len, HEX);
return opcode;
}
推荐阅读
- frontend - bootstrap 5 carousel 没有响应并且缺少文本
- haskell - Haskell 中的流数据类型实现
- java - 带有 kubernetes 的 Eureka 服务器
- azure - 如何在认知搜索索引器中翻译 Azure Blob 存储中的 HTML 文档?
- python - 例外:在 pyinstaller 中找不到 Python.Runtime
- javascript - TypeError: props.price.toFixed 不是函数。(在 'props.price.toFixed(2)' 中,'props.price.toFixed' 未定义)
- c# - 为什么在 C# 中从具有 double 类型的重复属性的列表中删除对象不会使用不同的方法给出一致的结果?
- amazon-ec2 - Promtail EC2 权限
- php - MySQLi 准备好的语句查询不会运行
- tensorflow - 基于索引张量从张量中选择值