Add socket.io client

This commit is contained in:
Kenta Kusumoto
2016-06-06 15:21:13 +03:00
parent 6a914fc5ea
commit f8a5acc9b7
5 changed files with 167 additions and 17 deletions

View File

@ -0,0 +1,113 @@
/*
* WebSocketClientSocketIO.ino
*
* Created on: 06.06.2016
*
*/
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <WebSocketsClient.h>
#include <Hash.h>
ESP8266WiFiMulti WiFiMulti;
WebSocketsClient webSocket;
#define USE_SERIAL Serial1
#define MESSAGE_INTERVAL 30000
#define HEARTBEAT_INTERVAL 25000
uint64_t messageTimestamp = 0;
uint64_t heartbeatTimestamp = 0;
bool isConnected = false;
void webSocketEvent(WStype_t type, uint8_t * payload, size_t lenght) {
switch(type) {
case WStype_DISCONNECTED:
USE_SERIAL.printf("[WSc] Disconnected!\n");
isConnected = false;
break;
case WStype_CONNECTED:
{
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
isConnected = true;
// send message to server when Connected
// socket.io upgrade confirmation message (required)
webSocket.sendTXT("5");
}
break;
case WStype_TEXT:
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
// send message to server
// webSocket.sendTXT("message here");
break;
case WStype_BIN:
USE_SERIAL.printf("[WSc] get binary lenght: %u\n", lenght);
hexdump(payload, lenght);
// send data to server
// webSocket.sendBIN(payload, lenght);
break;
}
}
void setup() {
// USE_SERIAL.begin(921600);
USE_SERIAL.begin(115200);
//Serial.setDebugOutput(true);
USE_SERIAL.setDebugOutput(true);
USE_SERIAL.println();
USE_SERIAL.println();
USE_SERIAL.println();
for(uint8_t t = 4; t > 0; t--) {
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
USE_SERIAL.flush();
delay(1000);
}
WiFiMulti.addAP("SSID", "passpasspass");
//WiFi.disconnect();
while(WiFiMulti.run() != WL_CONNECTED) {
delay(100);
}
webSocket.begin("192.168.0.123", 81);
//webSocket.setAuthorization("user", "Password"); // HTTP Basic Authorization
webSocket.onEvent(webSocketEvent);
}
void loop() {
webSocket.loop();
if(isConnected) {
uint64_t now = millis();
if(now - messageTimestamp > INTERVAL) {
messageTimestamp = now;
// example socket.io message with type "messageType" and JSON payload
webSocket.sendTXT("42[\"messageType\",{\"greeting\":\"hello\"}]");
}
if((now - heartbeatTimestamp) > HEARTBEAT_INTERVAL) {
heartbeatTimestamp = now;
// socket.io heartbeat message
webSocket.sendTXT("2");
}
}
}

View File

@ -296,7 +296,7 @@ bool WebSockets::handleWebsocketWaitFor(WSclient_t * client, size_t size) {
} }
if(size > WEBSOCKETS_MAX_HEADER_SIZE) { if(size > WEBSOCKETS_MAX_HEADER_SIZE) {
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocketWaitFor] size: %d to big!\n", client->num, size); DEBUG_WEBSOCKETS("[WS][%d][handleWebsocketWaitFor] size: %d too big!\n", client->num, size);
return false; return false;
} }
@ -364,7 +364,7 @@ void WebSockets::handleWebsocketCb(WSclient_t * client) {
} }
if(buffer[0] != 0 || buffer[1] != 0 || buffer[2] != 0 || buffer[3] != 0) { if(buffer[0] != 0 || buffer[1] != 0 || buffer[2] != 0 || buffer[3] != 0) {
// really to big! // really too big!
header->payloadLen = 0xFFFFFFFF; header->payloadLen = 0xFFFFFFFF;
} else { } else {
header->payloadLen = buffer[4] << 24 | buffer[5] << 16 | buffer[6] << 8 | buffer[7]; header->payloadLen = buffer[4] << 24 | buffer[5] << 16 | buffer[6] << 8 | buffer[7];
@ -377,7 +377,7 @@ void WebSockets::handleWebsocketCb(WSclient_t * client) {
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] mask: %u payloadLen: %u\n", client->num, header->mask, header->payloadLen); DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] mask: %u payloadLen: %u\n", client->num, header->mask, header->payloadLen);
if(header->payloadLen > WEBSOCKETS_MAX_DATA_SIZE) { if(header->payloadLen > WEBSOCKETS_MAX_DATA_SIZE) {
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] payload to big! (%u)\n", client->num, header->payloadLen); DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] payload too big! (%u)\n", client->num, header->payloadLen);
clientDisconnect(client, 1009); clientDisconnect(client, 1009);
return; return;
} }
@ -596,4 +596,3 @@ bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWait
#endif #endif
return true; return true;
} }

View File

@ -159,6 +159,8 @@ typedef struct {
WEBSOCKETS_NETWORK_CLASS * tcp; WEBSOCKETS_NETWORK_CLASS * tcp;
bool isSocketIO; ///< client for socket.io server
#if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
bool isSSL; ///< run in ssl mode bool isSSL; ///< run in ssl mode
WiFiClientSecure * ssl; WiFiClientSecure * ssl;
@ -170,6 +172,7 @@ typedef struct {
bool cIsUpgrade; ///< Connection == Upgrade bool cIsUpgrade; ///< Connection == Upgrade
bool cIsWebsocket; ///< Upgrade == websocket bool cIsWebsocket; ///< Upgrade == websocket
String cSessionId; ///< client Set-Cookie (session id)
String cKey; ///< client Sec-WebSocket-Key String cKey; ///< client Sec-WebSocket-Key
String cAccept; ///< client Sec-WebSocket-Accept String cAccept; ///< client Sec-WebSocket-Accept
String cProtocol; ///< client Sec-WebSocket-Protocol String cProtocol; ///< client Sec-WebSocket-Protocol

View File

@ -91,6 +91,14 @@ void WebSocketsClient::beginSSL(String host, uint16_t port, String url, String f
} }
#endif #endif
void WebSocketsClient::beginSocketIO(const char *host, uint16_t port, const char * url, const char * protocol) {
begin(host, port, url, protocol);
_client.isSocketIO = true;
}
void WebSocketsClient::beginSocketIO(String host, uint16_t port, String url, String protocol) {
beginSocketIO(host.c_str(), port, url.c_str(), protocol.c_str());
}
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) #if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
/** /**
@ -393,22 +401,37 @@ void WebSocketsClient::sendHeader(WSclient_t * client) {
unsigned long start = micros(); unsigned long start = micros();
#endif #endif
String handshake = "GET " + client->cUrl + " HTTP/1.1\r\n" String transport;
"Host: " + _host + ":" + _port + "\r\n" String handshake;
"Connection: Upgrade\r\n" if(!client->isSocketIO || (client->isSocketIO && client->cSessionId.length() > 0)) {
"Upgrade: websocket\r\n" if(client->isSocketIO) {
"Origin: file://\r\n" transport = "&transport=websocket&sid=" + client->cSessionId;
"User-Agent: arduino-WebSocket-Client\r\n" }
"Sec-WebSocket-Version: 13\r\n" handshake = "GET " + client->cUrl + transport + " HTTP/1.1\r\n"
"Sec-WebSocket-Key: " + client->cKey + "\r\n"; "Host: " + _host + ":" + _port + "\r\n"
"Connection: Upgrade\r\n"
"Upgrade: websocket\r\n"
"Origin: file://\r\n"
"User-Agent: arduino-WebSocket-Client\r\n"
"Sec-WebSocket-Version: 13\r\n"
"Sec-WebSocket-Key: " + client->cKey + "\r\n";
if(client->cProtocol.length() > 0) { if(client->cProtocol.length() > 0) {
handshake += "Sec-WebSocket-Protocol: " + client->cProtocol + "\r\n"; handshake += "Sec-WebSocket-Protocol: " + client->cProtocol + "\r\n";
}
if(client->cExtensions.length() > 0) {
handshake += "Sec-WebSocket-Extensions: " + client->cExtensions + "\r\n";
}
} else {
handshake = "GET " + client->cUrl + "&transport=polling HTTP/1.1\r\n"
"Connection: keep-alive\r\n";
} }
if(client->cExtensions.length() > 0) { handshake += "Host: " + _host + ":" + _port + "\r\n"
handshake += "Sec-WebSocket-Extensions: " + client->cExtensions + "\r\n"; "Origin: file://\r\n"
} "User-Agent: arduino-WebSocket-Client\r\n";
if(client->base64Authorization.length() > 0) { if(client->base64Authorization.length() > 0) {
handshake += "Authorization: Basic " + client->base64Authorization + "\r\n"; handshake += "Authorization: Basic " + client->base64Authorization + "\r\n";
@ -465,6 +488,8 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
client->cExtensions = headerValue; client->cExtensions = headerValue;
} else if(headerName.equalsIgnoreCase("Sec-WebSocket-Version")) { } else if(headerName.equalsIgnoreCase("Sec-WebSocket-Version")) {
client->cVersion = headerValue.toInt(); client->cVersion = headerValue.toInt();
} else if(headerName.equalsIgnoreCase("Set-Cookie")) {
client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1);
} }
} else { } else {
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header error (%s)\n", headerLine->c_str()); DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header error (%s)\n", headerLine->c_str());
@ -490,6 +515,7 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cProtocol: %s\n", client->cProtocol.c_str()); DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cProtocol: %s\n", client->cProtocol.c_str());
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cExtensions: %s\n", client->cExtensions.c_str()); DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cExtensions: %s\n", client->cExtensions.c_str());
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cVersion: %d\n", client->cVersion); DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cVersion: %d\n", client->cVersion);
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cSessionId: %s\n", client->cSessionId.c_str());
bool ok = (client->cIsUpgrade && client->cIsWebsocket); bool ok = (client->cIsUpgrade && client->cIsWebsocket);
@ -498,6 +524,10 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
case 101: ///< Switching Protocols case 101: ///< Switching Protocols
break; break;
case 200:
if(client->isSocketIO) {
break;
}
case 403: ///< Forbidden case 403: ///< Forbidden
// todo handle login // todo handle login
default: ///< Server dont unterstand requrst default: ///< Server dont unterstand requrst
@ -530,6 +560,8 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
runCbEvent(WStype_CONNECTED, (uint8_t *) client->cUrl.c_str(), client->cUrl.length()); runCbEvent(WStype_CONNECTED, (uint8_t *) client->cUrl.c_str(), client->cUrl.length());
} else if(clientIsConnected(client) && client->isSocketIO && client->cSessionId.length() > 0) {
sendHeader(client);
} else { } else {
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] no Websocket connection close.\n"); DEBUG_WEBSOCKETS("[WS-Client][handleHeader] no Websocket connection close.\n");
client->tcp->write("This is a webSocket client!"); client->tcp->write("This is a webSocket client!");

View File

@ -48,6 +48,9 @@ class WebSocketsClient: private WebSockets {
void beginSSL(String host, uint16_t port, String url = "/", String fingerprint = "", String protocol = "arduino"); void beginSSL(String host, uint16_t port, String url = "/", String fingerprint = "", String protocol = "arduino");
#endif #endif
void beginSocketIO(const char *host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino");
void beginSocketIO(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino");
#if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) #if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
void loop(void); void loop(void);
#else #else