Chapter 18 WebSocket Server for ESP32
Pay attention to the public account of Jiayouchuang Technology
- Source address: https://github.com/HX-IoT/ESP32-Developer-Guide
- ESP32 development guide QQ group: 824870185, there is a pdf version, and the layout is neat.
Learning goals and objectives
Master the principle and working process of Websocket
Master the programming of WebSocket of Espressif ESP32
WebSocket principle
WebSocket is a network communication protocol , a protocol provided by HTML5 for full-duplex communication on a single TCP connection.
Why do you need WebSockets?
Anyone who knows computer network protocols should know that the HTTP protocol is a stateless, connectionless, one-way application layer protocol. It adopts a request/response model. A communication request can only be initiated by the client, and the server responds to the request.
This communication model has a drawback: the HTTP protocol cannot enable the server to actively initiate messages to the client.
The characteristics of this one-way request are destined to be very troublesome for the client to know if the server has continuous state changes. Most web applications will implement long polling with frequent asynchronous JavaScript and XML (AJAX) requests. Polling is inefficient and wastes resources (because you have to keep connecting, or the HTTP connection is always open).
Therefore, engineers have been thinking, is there a better way. That's how WebSocket was invented. A WebSocket connection allows full-duplex communication between the client and server so that either side can push data to the other over the established connection. WebSocket only needs to establish a connection once, and it can stay connected all the time . Compared with the continuous establishment of connections in the polling method, the efficiency is obviously greatly improved.
Websocket Features
- Based on the TCP protocol, the server-side implementation is relatively easy.
- It has good compatibility with HTTP protocol. The default ports are also 80 and 443, and the HTTP protocol is used in the handshake phase, so it is not easy to shield during the handshake, and it can pass through various HTTP proxy servers.
- The data format is relatively lightweight, the performance overhead is small, and the communication is efficient.
- Text can be sent, or binary data can be sent.
- There is no same-origin restriction, and clients can communicate with any server.
The protocol identifier is ws (or wss if encrypted), and the server URL is the URL, as shown below.
1 2 3 4 5 6 7 8 | GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13 Origin: http://example.com |
request handshake
1 2 3 4 | HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat |
receive request packet
Note: Detailed WebSocket handshake
Websocket and HTTP connection process
Websocket working process
software design
Websocket detailed process of ESP32
Introduction to the Websocket interface of ESP32
- Connection function: netconn_new();
- Binding function: netconn_bind();
- Listening function: netconn_listen();
- Get the connection function: netconn_accept();
- Receive data function: netconn_recv();
- Send data function: netconn_write();
- Close the connection function: netconn_close();
- Delete connection function: netconn_delete();
For more detailed interfaces, please refer to the official guide .
Websocket new task writing
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | void ws_server(void *pvParameters) {undefined struct netconn *conn, *newconn; //Get tcp socket connect conn = netconn_new(NETCONN_TCP); //bind port netconn_bind(conn, NULL, WS_PORT); //monitor netconn_listen(conn); //Wait for client to connect while (netconn_accept(conn, &newconn) == ERR_OK) {undefined //New connection: waiting for connection, connection process, data read ws_server_netconn_serve(newconn); } //Close websocket server connect netconn_close(conn); netconn_delete(conn); } |
Websocket connection process code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | static void ws_server_netconn_serve(struct netconn *conn) {undefined //Apply for SHA1 p_SHA1_Inp = pvPortMallocCaps(WS_CLIENT_KEY_L + sizeof(WS_sec_conKey), MALLOC_CAP_8BIT); //Apply for SHA1 result p_SHA1_result = pvPortMallocCaps(SHA1_RES_L, MALLOC_CAP_8BIT); //Check if malloc suceeded if ((p_SHA1_Inp != NULL) && (p_SHA1_result != NULL)) {undefined //Receive data from the "connect" process if (netconn_recv(conn, &inbuf) == ERR_OK) {undefined //Read the data of the "connect" process to buf netbuf_data(inbuf, (void**) &buf, &i); //Pass the server's key to SHA1 for (i = 0; i < sizeof(WS_sec_conKey); i++) {undefined // put in the last 24 bytes p_SHA1_Inp[i + WS_CLIENT_KEY_L] = WS_sec_conKey[i]; } //Search the client's key p_buf = strstr(buf, WS_sec_WS_keys); //find key if (p_buf != NULL) {undefined //get Client Key for (i = 0; i < WS_CLIENT_KEY_L; i++) {undefined // put in the first 24 bytes p_SHA1_Inp[i] = *(p_buf + sizeof(WS_sec_WS_keys) + i); } // Calculate hash esp_sha(SHA1, (unsigned char*) p_SHA1_Inp, strlen(p_SHA1_Inp), (unsigned char*) p_SHA1_result); //Turn to base64 p_buf = (char*) _base64_encode((unsigned char*) p_SHA1_result, SHA1_RES_L, (size_t*) &i); //free SHA1 input free(p_SHA1_Inp); //free SHA1 result free(p_SHA1_result); if (p_payload != NULL) {undefined // prepare the "handshake" frame sprintf(p_payload, WS_srv_hs, i - 1, p_buf); //Send the "handshake" frame netconn_write(conn, p_payload, strlen(p_payload),NETCONN_COPY); //free base64 free(p_buf); //free "handshake" memory free(p_payload); //websocket connection is successful WS_conn = conn; //"Receive data" while (netconn_recv(conn, &inbuf) == ERR_OK) {undefined . . . . . . |
Websocket send code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | err_t WS_write_data(char* p_data, size_t length) {undefined //websocket is not connected, exit directly if (WS_conn == NULL) return ERR_CONN; //Data frame length overflow, exit directly if (length > WS_STD_LEN) return ERR_VAL; err_t result; // header WS_frame_header_t hdr; hdr.FIN = 0x1; hdr.payload_length = length; hdr.mask = 0; hdr.reserved = 0; hdr.opcode = WS_OP_TXT; // send header result = netconn_write(WS_conn, &hdr, sizeof(WS_frame_header_t), NETCONN_COPY); if (result != ERR_OK) return result; //send data return netconn_write(WS_conn, p_data, length, NETCONN_COPY); } |
The code has all Chinese comments
Test process and effect display
test process
- Change the STA account password
- WebSocket Testing Using Computer Assistant Tool
Show results
connect
send
control lights
Disconnect
WebSocketSummary
- This source code is mainly to learn the whole process of WebSocket. In fact, there are still many places that can be improved. After understanding WebSocket, you can fly to the sky by yourself.
- Source address: https://github.com/xiaolongba/wireless-tech