首页 > 解决方案 > 通过 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 后立即发送消息。

请给我一些见解:)

标签: websocketesp8266at-command

解决方案


我找到了一种解决方案。

事实上,我并不了解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;
}

推荐阅读