我正在与 ESP8266 Wifi 模块接口的 STM32F070 微控制器上开发一个小型物联网项目。我在 STM32F070 控制器上开发了一个 Websocket 客户端应用程序,它将与远程 Websocket 服务器通信并通过连接交换数据。
我从 Websocket 客户端与服务器建立 TCP 连接,但在发送 Websocket 请求标头后,我收到来自服务器的 HTTP/1.1 400 Bad Request 并且连接被关闭。
以下是来自 ESP8266 UART 线路的日志:
ready
WIFI CONNECTED
WIFI GOT IP
AT
OK
ATE0
OK
OK
WIFI DISCONNECT
WIFI CONNECTED
WIFI GOT IP
OK
+CIFSR:STAIP,"192.168.43.194"
+CIFSR:STAMAC,"48:3f:da:66:cf:2c"
OK
OK
ERROR
CLOSED
ERROR
CLOSED
CONNECT
OK
OK
>
Recv 227 bytes
SEND OK
+IPD,103:HTTP/1.1 400 Bad Request
Connection: close
Content-Type: text/html
Content-Length: 11
Bad RequestCLOSED
这是我发送到远程 Websocket 服务器的标头
AT+RST
AT
ATE0
AT+CWMODE=1
AT+CWJAP="Txxxxx","08080808"
AT+CIFSR
AT+CIPMUX=0
AT+CIPSTART="TCP","192.168.43.69",8080
AT+CIPSEND=227
GET / HTTP/1.1
Host: 192.168.43.69:8080
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: NhEEf0jUzTLT3ZC2jSW1PnsX
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
编辑:STM32F070 Source Code to send Websocket Headers to server over ESP8266
// 1) Generating WebSocket Header:
//Generate a random key.
Base64_GetRandomKey( webSock.LocalKey );
//Reset the flag so we can check in response.
webSock.ServerKeyOK = 0;
//Host IP:
ip3 = ( dev.NetServerIP_Addr >> 24 ) & 0xFF;
ip2 = ( dev.NetServerIP_Addr >> 16 ) & 0xFF;
ip1 = ( dev.NetServerIP_Addr >> 8 ) & 0xFF;
ip0 = ( dev.NetServerIP_Addr ) & 0xFF;
//Make the HTML headers.
len += snprintf( &buf[len], HTTP_BUFFER_LEN_MAX - len, ( HTTP_PAGE_QUERY_REM_SRV_GET_HDR ), ip3, ip2, ip1, ip0, dev.NetServerPort );
len += snprintf( &buf[len], HTTP_BUFFER_LEN_MAX - len, ( HTTP_PAGE_QUERY_REM_SRV_GET_BODY ), webSock.LocalKey );
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 2) Send Data Header to ESP8266, send Data Length with AT+CIPSEND AT Command
//Send the IP data header during data send.
static void ESP8266_SendDataHeader( ESP_Con *connection )
{
char buf[64];
sprintf( buf, "AT+CIPSEND=%d\r\n", connection->IPD_Len );
Esp8266TransmitWith( buf );
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 3) Send Data after getting '>' char from ESP8266
//Wait for the data prompt.
len = FIFO2_GetCharsUntil( &espUsart.rxFIFO, esp.buffer, ESP_DATA_BUFFER_LEN, '>' );
if( len > 0 && strstr( esp.buffer, ( ">" ) ) != NULL ) //Got the prompt to send data.
{
esp.timeout = EspConnectionTimeOutMed;
FIFO2_Flush(&espUsart.rxFIFO, 0 );
esp.state = EspStateSendDataReady;
}
else if( esp.timeout > ESP_TASK_INTERVAL )
{
esp.timeout -= ESP_TASK_INTERVAL;
}
else if( esp.retry > ESP_SEND_DATA_RETRY_MAX )
{
esp.state = EspStateIpClose;
}
else
{
esp.state = EspStateSendData;
// Sending Header Data to ESP8266 from Here
}
源代码中的 HTTP 标头:
"GET / HTTP/1.1\r\nHost: %d.%d.%d.%d:%d\r\n"
"Connection: Upgrade\r\n"\
"Upgrade: websocket\r\n"\
"Sec-WebSocket-Version: 13\r\n"\
"Sec-WebSocket-Key: %s\r\n"\
"Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n\r\n"
这是 Node Js 中的 WebSocket 服务器代码。
var bodyParser = require("body-parser");
const express = require('express'); //express framework to have a higher level of methods
const app = express(); //assign app variable the express class/method
var http = require('http');
var path = require("path");
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
const server = http.createServer(app);//create a server
//***************this snippet gets the local ip of the node.js server. copy this ip to the client side code and add ':3000' *****
//****************exmpl. 192.168.56.1---> var sock =new WebSocket("ws://192.168.56.1:3000");*************************************
require('dns').lookup(require('os').hostname(), function (err, add, fam) {
console.log('addr: '+add);
})
/**********************websocket setup**************************************************************************************/
//var expressWs = require('express-ws')(app,server);
const WebSocket = require('ws');
const s = new WebSocket.Server({ server });
s.on('connection', function(ws, req) {
console.log(req.headers);
console.log(req.params);
});
//when browser sends get request, send html file to browser
// viewed at http://localhost:30000
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname + '/index.html'));
});
//*************************************************************************************************************************
//***************************ws chat server********************************************************************************
//app.ws('/echo', function(ws, req) {
s.on('connection',function(ws,req){
/******* when server receives messsage from client trigger function with argument message *****/
ws.on('message',function(message){
console.log("Received: "+message);
s.clients.forEach(function(client){ //broadcast incoming message to all clients (s.clients)
if(client!=ws && client.readyState ){ //except to the same client (ws) that sent this message
client.send("broadcast: " +message);
}
});
// ws.send("From Server only to sender: "+ message); //send to client where message is from
});
ws.on('close', function(){
console.log("lost one client");
});
//ws.send("new client connected");
console.log("new client connected");
});
server.listen(8080);
NodeJs WebSocket Server 使用 Mobile WebsocketClient Tester Android Application进行测试。它工作正常
编辑2:
我尝试连接http://echo.websocket.org/,我修改了代码以连接http://echo.websocket.org/。我可以成功连接http://echo.websocket.org/。收到来自http://echo.websocket.org/的响应
这里是日志供参考。
GET / HTTP/1.1
Host: echo.websocket.org
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: Dh6EV0ZUpTBTtZ42ZSM1FniX
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
+IPD,201:HTTP/1.1 101 Web Socket Protocol Handshake
Connection: Upgrade
Date: Sun, 23 May 2021 08:54:52 GMT
Sec-WebSocket-Accept: TaHsjyffJhTaBluq4Bmksq0NPWo=
Server: Kaazing Gateway
Upgrade: websocket