up
This commit is contained in:
parent
f88a41b312
commit
0b23bfb177
3 changed files with 28 additions and 27 deletions
|
@ -76,7 +76,7 @@ During the connection the browser (using headers) asks the server: "Do you suppo
|
|||
|
||||

|
||||
|
||||
Here's an example of browser request for `new WebSocket("wss://javascript.info/chat")`.
|
||||
Here's an example of browser headers for request made by `new WebSocket("wss://javascript.info/chat")`.
|
||||
|
||||
```
|
||||
GET /chat
|
||||
|
@ -117,17 +117,15 @@ There may be additional headers `Sec-WebSocket-Extensions` and `Sec-WebSocket-Pr
|
|||
|
||||
For instance:
|
||||
|
||||
- `Sec-WebSocket-Extensions: deflate-frame` means that the browser supports data compression. An extension is something related to transferring the data, not data itself.
|
||||
- `Sec-WebSocket-Extensions: deflate-frame` means that the browser supports data compression. An extension is something related to transferring the data, functionality that extends WebSocket protocol. The header `Sec-WebSocket-Extensions` is sent automatically by the browser, with the list of all extenions it supports.
|
||||
|
||||
- `Sec-WebSocket-Protocol: soap, wamp` means that we'd like to transfer not just any data, but the data in [SOAP](http://en.wikipedia.org/wiki/SOAP) or WAMP ("The WebSocket Application Messaging Protocol") protocols. WebSocket subprotocols are registered in the [IANA catalogue](http://www.iana.org/assignments/websocket/websocket.xml).
|
||||
|
||||
`Sec-WebSocket-Extensions` header is sent by the browser automatically, with a list of possible extensions it supports.
|
||||
This optional header is set by us, to tell the server which subprotocols our code supports, using the second (optional) parameter of `new WebSocket`. That's the array of subprotocols, e.g. if we'd like to use SOAP or WAMP:
|
||||
|
||||
`Sec-WebSocket-Protocol` header depends on us: we decide what kind of data we send. The second optional parameter of `new WebSocket` is just for that, it lists subprotocols:
|
||||
|
||||
```js
|
||||
let socket = new WebSocket("wss://javascript.info/chat", ["soap", "wamp"]);
|
||||
```
|
||||
```js
|
||||
let socket = new WebSocket("wss://javascript.info/chat", ["soap", "wamp"]);
|
||||
```
|
||||
|
||||
The server should respond with a list of protocols and extensions that it agrees to use.
|
||||
|
||||
|
@ -162,24 +160,24 @@ Sec-WebSocket-Protocol: soap
|
|||
|
||||
Here the server responds that it supports the extension "deflate-frame", and only SOAP of the requested subprotocols.
|
||||
|
||||
## WebSocket data
|
||||
## Data transfer
|
||||
|
||||
WebSocket communication consists of "frames" -- data fragments, that can be sent from either side, and can be of several kinds:
|
||||
|
||||
- "text frames" -- contain text data that parties send to each other.
|
||||
- "binary data frames" -- contain binary data that parties send to each other.
|
||||
- "ping/pong frames" are used to check the connection, sent from the server, the browser responds to these automatically.
|
||||
- "connection close frame" and a few other service frames.
|
||||
- there's also "connection close frame" and a few other service frames.
|
||||
|
||||
In the browser, we directly work only with text or binary frames.
|
||||
|
||||
**WebSocket `.send()` method can send either text or binary data.**
|
||||
|
||||
A call `socket.send(body)` allows `body` in string or a binary format, including `Blob`, `ArrayBuffer`, etc. No settings required: just send it out.
|
||||
A call `socket.send(body)` allows `body` in string or a binary format, including `Blob`, `ArrayBuffer`, etc. No settings required: just send it out in any format.
|
||||
|
||||
**When we receive the data, text always comes as string. And for binary data, we can choose between `Blob` and `ArrayBuffer` formats.**
|
||||
|
||||
The `socket.bufferType` is `"blob"` by default, so binary data comes in Blobs.
|
||||
That's set by `socket.bufferType` property, it's `"blob"` by default, so binary data comes as `Blob` objects.
|
||||
|
||||
[Blob](info:blob) is a high-level binary object, it directly integrates with `<a>`, `<img>` and other tags, so that's a sane default. But for binary processing, to access individual data bytes, we can change it to `"arraybuffer"`:
|
||||
|
||||
|
@ -192,7 +190,7 @@ socket.onmessage = (event) => {
|
|||
|
||||
## Rate limiting
|
||||
|
||||
Imagine, our app is generating a lot of data to send. But the user has a slow network connection, maybe on a mobile, outside of a city.
|
||||
Imagine, our app is generating a lot of data to send. But the user has a slow network connection, maybe on a mobile internet, outside of a city.
|
||||
|
||||
We can call `socket.send(data)` again and again. But the data will be buffered (stored) in memory and sent out only as fast as network speed allows.
|
||||
|
||||
|
@ -249,7 +247,7 @@ There are other codes like:
|
|||
- `1011` -- unexpected error on server,
|
||||
- ...and so on.
|
||||
|
||||
Please refer to the [RFC6455, §7.4.1](https://tools.ietf.org/html/rfc6455#section-7.4.1) for the full list.
|
||||
The full list can be found in [RFC6455, §7.4.1](https://tools.ietf.org/html/rfc6455#section-7.4.1).
|
||||
|
||||
WebSocket codes are somewhat like HTTP codes, but different. In particular, any codes less than `1000` are reserved, there'll be an error if we try to set such a code.
|
||||
|
||||
|
@ -275,9 +273,9 @@ To get connection state, additionally there's `socket.readyState` property with
|
|||
|
||||
## Chat example
|
||||
|
||||
Let's review a chat example using browser WebSocket API and Node.js WebSocket module <https://github.com/websockets/ws>.
|
||||
Let's review a chat example using browser WebSocket API and Node.js WebSocket module <https://github.com/websockets/ws>. We'll pay the main attention to the client side, but the server is also simple.
|
||||
|
||||
HTML: there's a `<form>` to send messages and a `<div>` for incoming messages:
|
||||
HTML: we need a `<form>` to send messages and a `<div>` for incoming messages:
|
||||
|
||||
```html
|
||||
<!-- message form -->
|
||||
|
@ -290,7 +288,12 @@ HTML: there's a `<form>` to send messages and a `<div>` for incoming messages:
|
|||
<div id="messages"></div>
|
||||
```
|
||||
|
||||
JavaScript is also simple. We open a socket, then on form submission -- `socket.send(message)`, on incoming message -- append it to `div#messages`:
|
||||
From JavaScript we want three things:
|
||||
1. Open the connection.
|
||||
2. On form submission -- `socket.send(message)` for the message.
|
||||
3. On incoming message -- append it to `div#messages`.
|
||||
|
||||
Here's the code:
|
||||
|
||||
```js
|
||||
let socket = new WebSocket("wss://javascript.info/article/websocket/chat/ws");
|
||||
|
@ -303,7 +306,7 @@ document.forms.publish.onsubmit = function() {
|
|||
return false;
|
||||
};
|
||||
|
||||
// show message in div#messages
|
||||
// message received - show the message in div#messages
|
||||
socket.onmessage = function(event) {
|
||||
let message = event.data;
|
||||
|
||||
|
@ -313,13 +316,12 @@ socket.onmessage = function(event) {
|
|||
}
|
||||
```
|
||||
|
||||
Server-side code is a little bit beyond our scope here. We're using browser WebSocket API, a server may have another library.
|
||||
|
||||
Still it can also be pretty simple. We'll use Node.js with <https://github.com/websockets/ws> module for websockets.
|
||||
Server-side code is a little bit beyond our scope. Here we'll use Node.js, but you don't have to. Other platforms also have their means to work with WebSocket.
|
||||
|
||||
The server-side algorithm will be:
|
||||
|
||||
1. Create `clients = new Set()` -- a set of sockets.
|
||||
2. For each accepted websocket, `clients.add(socket)` and add `message` event listener for its messages.
|
||||
2. For each accepted websocket, add it to the set `clients.add(socket)` and setup `message` event listener to get its messages.
|
||||
3. When a message received: iterate over clients and send it to everyone.
|
||||
4. When a connection is closed: `clients.delete(socket)`.
|
||||
|
||||
|
@ -359,7 +361,6 @@ Here's the working example:
|
|||
|
||||
You can also download it (upper-right button in the iframe) and run locally. Just don't forget to install [Node.js](https://nodejs.org/en/) and `npm install ws` before running.
|
||||
|
||||
|
||||
## Summary
|
||||
|
||||
WebSocket is a modern way to have persistent browser-server connections.
|
||||
|
@ -384,4 +385,4 @@ WebSocket by itself does not include reconnection, authentication and many other
|
|||
|
||||
Sometimes, to integrate WebSocket into existing project, people run WebSocket server in parallel with the main HTTP-server, and they share a single database. Requests to WebSocket use `wss://ws.site.com`, a subdomain that leads to WebSocket server, while `https://site.com` goes to the main HTTP-server.
|
||||
|
||||
Surely, other ways of integration are also possible. Many servers (such as Node.js) can support both HTTP and WebSocket protocols.
|
||||
Surely, other ways of integration are also possible.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="429px" height="404px" viewBox="0 0 429 404" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<svg width="429px" height="348px" viewBox="0 0 429 348" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: sketchtool 55.2 (78181) - https://sketchapp.com -->
|
||||
<title>websocket-handshake.svg</title>
|
||||
<desc>Created with sketchtool.</desc>
|
||||
|
@ -18,7 +18,7 @@
|
|||
<path id="Line" d="M349,141 L68,141 L68,139 L349,139 L349,133 L363,140 L349,147 L349,141 Z" fill="#EE6B47" fill-rule="nonzero"></path>
|
||||
<path id="Line-Copy" d="M83,210 L364,210 L364,212 L83,212 L83,218 L69,211 L83,204 L83,210 Z" fill="#EE6B47" fill-rule="nonzero"></path>
|
||||
<text id="HTTP-request" font-family="OpenSans-Regular, Open Sans" font-size="14" font-weight="normal" line-spacing="22" fill="#8A704D">
|
||||
<tspan x="171.515137" y="130">HTTP-request</tspan>
|
||||
<tspan x="172.015137" y="130">HTTP-request</tspan>
|
||||
</text>
|
||||
<text id=""Hey,-server,-let's" font-family="OpenSans-Regular, Open Sans" font-size="14" font-weight="normal" line-spacing="22" fill="#8A704D">
|
||||
<tspan x="103.374512" y="161">"Hey, server, let's talk WebSocket?"</tspan>
|
||||
|
@ -29,7 +29,7 @@
|
|||
</text>
|
||||
<path id="Line-Copy-2" d="M81,278 L83,278 L83,280 L81,280 L81,286 L67,279 L81,272 L81,278 Z M363,279 L349,286 L349,272 L363,279 Z M85,280 L85,278 L89,278 L89,280 L85,280 Z M91,280 L91,278 L95,278 L95,280 L91,280 Z M97,280 L97,278 L101,278 L101,280 L97,280 Z M103,280 L103,278 L107,278 L107,280 L103,280 Z M109,280 L109,278 L113,278 L113,280 L109,280 Z M115,280 L115,278 L119,278 L119,280 L115,280 Z M121,280 L121,278 L125,278 L125,280 L121,280 Z M127,280 L127,278 L131,278 L131,280 L127,280 Z M133,280 L133,278 L137,278 L137,280 L133,280 Z M139,280 L139,278 L143,278 L143,280 L139,280 Z M145,280 L145,278 L149,278 L149,280 L145,280 Z M151,280 L151,278 L155,278 L155,280 L151,280 Z M157,280 L157,278 L161,278 L161,280 L157,280 Z M163,280 L163,278 L167,278 L167,280 L163,280 Z M169,280 L169,278 L173,278 L173,280 L169,280 Z M175,280 L175,278 L179,278 L179,280 L175,280 Z M181,280 L181,278 L185,278 L185,280 L181,280 Z M187,280 L187,278 L191,278 L191,280 L187,280 Z M193,280 L193,278 L197,278 L197,280 L193,280 Z M199,280 L199,278 L203,278 L203,280 L199,280 Z M205,280 L205,278 L209,278 L209,280 L205,280 Z M211,280 L211,278 L215,278 L215,280 L211,280 Z M217,280 L217,278 L221,278 L221,280 L217,280 Z M223,280 L223,278 L227,278 L227,280 L223,280 Z M229,280 L229,278 L233,278 L233,280 L229,280 Z M235,280 L235,278 L239,278 L239,280 L235,280 Z M241,280 L241,278 L245,278 L245,280 L241,280 Z M247,280 L247,278 L251,278 L251,280 L247,280 Z M253,280 L253,278 L257,278 L257,280 L253,280 Z M259,280 L259,278 L263,278 L263,280 L259,280 Z M265,280 L265,278 L269,278 L269,280 L265,280 Z M271,280 L271,278 L275,278 L275,280 L271,280 Z M277,280 L277,278 L281,278 L281,280 L277,280 Z M283,280 L283,278 L287,278 L287,280 L283,280 Z M289,280 L289,278 L293,278 L293,280 L289,280 Z M295,280 L295,278 L299,278 L299,280 L295,280 Z M301,280 L301,278 L305,278 L305,280 L301,280 Z M307,280 L307,278 L311,278 L311,280 L307,280 Z M313,280 L313,278 L317,278 L317,280 L313,280 Z M319,280 L319,278 L323,278 L323,280 L319,280 Z M325,280 L325,278 L329,278 L329,280 L325,280 Z M331,280 L331,278 L335,278 L335,280 L331,280 Z M337,280 L337,278 L341,278 L341,280 L337,280 Z M343,280 L343,278 L347,278 L347,280 L343,280 Z" fill="#EE6B47" fill-rule="nonzero"></path>
|
||||
<text id="WebSocket-protocol" font-family="OpenSans-Regular, Open Sans" font-size="14" font-weight="normal" fill="#8A704D">
|
||||
<tspan x="151.524414" y="272">WebSocket protocol</tspan>
|
||||
<tspan x="152.024414" y="272">WebSocket protocol</tspan>
|
||||
</text>
|
||||
</g>
|
||||
</g>
|
||||
|
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
Loading…
Add table
Add a link
Reference in a new issue