IoT(Internet Of Things)
A web page normally talks to its server with HTTP requests, and each request gets exactly one response. That model does not fit an IoT dashboard or a chat window, where the server must push data at any time. WebSocket solves this with one long-lived, two-way connection. This page explains what WebSocket is and walks through a real opening handshake from an MQTT client in a browser. Then it shows how data is framed on the open connection.
What is WebSocket ?
WebSocket sounds like "A special socket that is specially designed/optimized for Web Application". It sounds OK.. but what it really mean ? The official definition of WebSocket is defined in RFC 6455 as stated below.
The WebSocket Protocol enables two-way communication between a client running untrusted code in a controlled environment to a remote host that has opted-in to communications from that code. The security model used for this is the origin-based security model commonly used by web browsers. The protocol consists of an opening handshake followed by basic message framing, layered over TCP. The goal of this technology is to provide a mechanism for browser-based applications that need two-way communication with servers that does not rely on opening multiple HTTP connections (e.g., using XMLHttpRequest or <iframe>s and long polling).
Whenever I try to clearly understand anything from RFC, I almost always have to rewrite things on my own format / words, otherwise it tend to be very confusing. Let me rewrite this statement from RFC document. It goes as follows.
- WebSocket is a kind of two-way communication between a client and a remote host
- The client is running untrusted code in a controlled environment and the remote host has opted-in to communication from that code.
- WebSocket uses the origin-based security model
- WebSocket protocol is layered over TCP
- Overal protocol sequence of WebSocket is
- Opening Handshake
- Basic Message Framing
- The WebSocket Protocol is an independent TCP-based protocol. Its only relationship to HTTP is that its handshake is interpreted by HTTP servers as an Upgrade request (RFC 6455 1.7. Relationship to TCP and HTTP)
Opening Handshake
Every WebSocket connection starts as an ordinary HTTP request on a TCP connection. The client asks the server to upgrade that connection, and the server agrees with status code 101. The table below lists the two messages, and the captures after it show every header they carry.
|
|
Direction |
Message |
|
(1) |
Client --> Server |
GET /protocol HTTP/1.1 (Host url etc) |
|
(2) |
Client <-- Server |
HTTP/1.1 101 Switching Protocols |
(1) GET /protocol HTTP/1.1 (Host url etc)
Captured HTTP request,
GET /mqtt HTTP/1.1 Host: broker.mqttdashboard.com:8000 Connection: Upgrade Pragma: no-cache Cache-Control: no-cache Upgrade: websocket Origin: http://www.hivemq.com Sec-WebSocket-Version: 13 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36 Accept-Encoding: gzip, deflate, sdch Accept-Language: en-US,en;q=0.8 Sec-WebSocket-Key: OfMWmQZlMFBWe/o7k1CzZg== Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits Sec-WebSocket-Protocol: mqttv3.1
The request is a normal HTTP GET, but the highlighted headers turn it into a WebSocket request. Connection: Upgrade and Upgrade: websocket ask the server to switch protocols on this TCP connection. Sec-WebSocket-Version: 13 is the version defined in RFC 6455. Sec-WebSocket-Key is 16 random bytes in base64, and the client picks a new one for every connection.
Two more headers matter for this capture. Sec-WebSocket-Protocol names the application protocol the client wants to run inside WebSocket, here mqttv3.1. Origin tells the server which web page opened the connection, and this is how the origin-based security model from the RFC works in practice. The server can refuse a connection from an origin it does not trust. The client also offers compression with Sec-WebSocket-Extensions: permessage-deflate.
(2) HTTP/1.1 101 Switching Protocols
Captured HTTP response,
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: PqfV+Vb3mDtpMlZ/bO+GBzyX4N8= Sec-WebSocket-Protocol: mqttv3.1
Let's check the one header that proves the server understood the request. The server takes the Sec-WebSocket-Key, appends the fixed GUID 258EAFA5-E914-47DA-95CA-C5AB0DC85B11, computes SHA-1 over the result, and encodes it in base64. For the key OfMWmQZlMFBWe/o7k1CzZg== this gives PqfV+Vb3mDtpMlZ/bO+GBzyX4N8=, which is exactly the Sec-WebSocket-Accept value in the capture. The client repeats this calculation, and it closes the connection if the values differ.
Also compare what the response leaves out. The server repeats Sec-WebSocket-Protocol: mqttv3.1, so the two sides agree to run MQTT. But the response carries no Sec-WebSocket-Extensions header, so compression was not agreed. From this point, the same TCP connection carries WebSocket frames instead of HTTP.
The handshake is an HTTP Upgrade : it lets WebSocket pass through ports, proxies and servers that already handle HTTP.Sec-WebSocket-Accept proves the server read the request : it is the base64 SHA-1 of the client key plus a fixed GUID.The server confirms only what it supports : here it accepted the mqttv3.1 subprotocol and declined permessage-deflate.
How is data framed after the handshake ?
After the 101 response, HTTP is gone and both sides exchange WebSocket frames. Each frame has a small header of 2 to 14 bytes. So a sensor value or an MQTT packet travels with much less overhead than an HTTP request with its headers.
Field |
Size |
Meaning |
FIN | 1 bit | 1 when this frame is the last fragment of a message |
RSV1, RSV2, RSV3 | 3 bits | 0 unless an extension defines them |
Opcode | 4 bits | 0x0 continuation, 0x1 text, 0x2 binary, 0x8 close, 0x9 ping, 0xA pong |
MASK | 1 bit | 1 when a Masking-key is present |
Payload length | 7 bits | 0 to 125 is the length itself. 126 means a 16-bit length follows, and 127 means a 64-bit length follows |
Masking-key | 0 or 4 bytes | Present when MASK is 1 |
Payload data | variable | Application data, masked when MASK is 1 |
The masking rule has a direction. A client must mask every frame it sends to the server, and a server must never mask the frames it sends to the client. The client XORs the payload with a new 4-byte Masking-key in each frame. This is not encryption, because the key travels in the same frame. Its purpose is to stop a browser from sending bytes that an old proxy could mistake for an HTTP request.
The opcode separates data frames from control frames. MQTT over WebSocket uses binary frames, opcode 0x2, because an MQTT packet is binary. Ping and pong frames check that the connection is still alive. To end the session, one side sends a close frame, the other side answers with its own close frame, and then the TCP connection is closed.
The frame header is small : 2 bytes for a short unmasked payload, and at most 14 bytes.Only client frames are masked : the Masking-key protects proxies, and it does not protect the data.MQTT rides in binary frames : each WebSocket message carries MQTT packets that the broker reads as if they came over plain TCP.