Обзор веб-сокета HTML5
Как веб-стандарт нового поколения, HTML5 предоставляет нам множество полезных вещей, таких как холст, локальное хранилище (которое было выделено), интерфейс мультимедийного программирования и, конечно же, наш WebSocket. WebSocket — это сетевая технология полнодуплексной связи (full-duplex) между браузерами и серверами, которую начал предоставлять HTML5, и может передавать текстовые и двоичные данные на основе информации. Он был стандартизирован IETF в 2011 году как RFC 6455, а API WebSocket также был стандартизирован W3C.
1. Предыстория WebSocket
1. Тьма перед рассветом — потребность в веб-приложениях реального времени
Я думаю, что все более-менее знают о процессе информационного взаимодействия веб-приложений.Обычно клиент отправляет запрос через браузер, а затем сервер принимает и проверяет запрос, обрабатывает его и возвращает результат клиенту.Браузер клиента выдает информацию. Этот коммуникационный механизм не представляет большой проблемы, когда информационное взаимодействие не особенно частое, но для тех приложений с высокими требованиями к реальному времени и массивным параллелизмом данных он кажется растянутым, например, для обычных веб-игр, веб-сайтов ценных бумаг. , RSS подписка, диалог в реальном времени на веб-странице, программное обеспечение такси и т. д. Часто к тому времени, когда клиент готов предоставить какую-либо информацию, эта информация, скорее всего, уже устарела на сервере. Чтобы соответствовать описанным выше сценариям, большие ребята придумали несколько компромиссных решений.Наиболее часто используемые из них - это обычный опрос и технология Comet, а технология Comet на самом деле является улучшением опроса.Comet можно разделить на два типа:
- длинный механизм опроса
- Механизм потоковой передачи
1.1 Длинный механизм опроса
Длительный опрос — это улучшение и расширение обычного опроса. Проще говоря, обычный опрос означает, что клиент отправляет запросы на сервер через равные промежутки времени, чтобы поддерживать синхронизацию между клиентом и сервером в виде частых запросов. Самая большая проблема с этой схемой синхронизации заключается в том, что когда клиент отправляет запросы с фиксированной частотой, очень вероятно, что данные на сервере не обновляются, что приводит к большому количеству бесполезной сетевой передачи, что очень неэффективно.
Чтобы уменьшить недопустимую передачу по сети, длительный опрос улучшает и улучшает обычный опрос.Когда нет обновления данных на стороне сервера, ссылка будет оставаться в течение определенного периода времени, пока не изменятся данные или состояние или не истечет время соединения.Механизм, который мы может уменьшить много неэффективного взаимодействия между клиентом и сервером. Конечно, если данные на стороне сервера меняются очень часто, этот механизм не дает эффективного повышения производительности и мало чем отличается от обычного опроса, а длительный опрос также будет потреблять больше ресурсов, таких как ЦП, память, пропускная способность и т. д. .
1.2 Механизм потоковой передачи
Механизм потоковой передачи заключается просто в том, что страница клиента использует скрытое окно для отправки на сервер запроса на длительное соединение. Сервер отвечает после получения запроса и постоянно обновляет статус, чтобы гарантировать, что соединение между клиентом и сервером не истечет. С помощью этого механизма информация на стороне сервера может непрерывно передаваться клиенту, тем самым обеспечивая своевременность информации. Однако этот механизм не удобен для пользователя, и для улучшения взаимодействия с пользователем необходимо обновлять различные решения для разных браузеров. ресурсы сервера.
2. Приход рассвета — WebSocket
Именно потому, что вышеупомянутые решения имеют свои ограничения, появился HTML5 WebSocket.Браузер может отправить запрос на подключение WebSocket к серверу через JavaScript с помощью существующего протокола HTTP.Когда соединение установлено, клиент и сервер может обмениваться данными напрямую через TCP-соединение. Это связано с тем, что протокол веб-сокета по сути является TCP-соединением, поэтому стабильность и объем передачи данных гарантируются, и по сравнению с предыдущими технологиями опроса и Comet производительность также значительно улучшилась:
Следует отметить, что, хотя веб-сокет должен использовать HTTP для связи, он существенно отличается от HTTP:
- WebSocket — это протокол двусторонней связи.После установления соединения как сервер WebSocket, так и клиент могут активно отправлять или получать данные друг другу.
- WebSocket необходимо сначала подключить, и только после повторного подключения он сможет взаимодействовать друг с другом.
Их отношения на самом деле такие же, как показано на этой картинке.Хотя есть пересекающиеся части, все же есть большая разница:
2. Использование WebSocket API
Поскольку у каждого серверного языка есть свой собственный API, давайте сначала обсудим клиентский API:
// 创建一个socket实例:
const socket = new WebSocket(ws://localhost:9093')
// 打开socket
socket.onopen = (event) => {
// 发送一个初始化消息
socket.send('Hello Server!')
// 服务器有响应数据触发
socket.onmessage = (event) => {
console.log('Client received a message',event)
}
// 出错时触发,并且会关闭连接。这时可以根据错误信息进行按需处理
socket.onerror = (event) => {
console.log('error')
}
// 监听Socket的关闭
socket.onclose = (event) => {
console.log('Client notified socket has closed',event)
}
// 关闭Socket
socket.close(1000, 'closing normally')
}
Считаете ли вы, что API, предоставляемый веб-сокетом HTML5, прост? Да, это так просто. Но есть несколько вещей, на которые мы должны обратить внимание:
- При создании экземпляра сокета new WebSocket() принимает два параметра: первый параметр — это ws или wss, а второй параметр может быть необязательным пользовательским протоколом, а если он мультипротокольный, то может быть массивом.
- Метод send в WebSocket не может отправлять какие-либо данные.Теперь можно отправлять только три типа данных, включая строковый тип UTF-8 (который по умолчанию будет преобразован в USVString), ArrayBuffer и Blob, и может использоваться только после установления соединения. учредил. (Спасибо большому парню за указание на ошибку, она была изменена)
- При использовании socket.close(код,[причина]) для закрытия соединения и код, и причина являются необязательными. code — числовое значение, указывающее номер состояния закрытого соединения, указывающее причину, по которой соединение было закрыто. Если этот параметр не указан, значение по умолчанию равно 1000 (указывающее, что соединение было закрыто нормально), а причина — это читаемая строка, указывающая причину, по которой соединение было закрыто. Эта строка должна быть текстом UTF-8 не длиннее 123 байт.
1. вс и всс
Как мы упоминали выше, при создании экземпляра сокета вы можете дополнительно заполнить ws и wss для определения протокола связи. Два из них на самом деле очень похожи на отношения между HTTP и HTTPS. Где ws означает связь в виде обычного текста, а wss означает использование зашифрованного канала связи (TCP+TLS). Так почему бы не использовать HTTP напрямую и не настроить протокол связи? Это из цели WebSocket.Основная функция WebSocket заключается в обеспечении оптимизированного, двустороннего механизма связи для приложения в браузере и на стороне сервера, но это не означает, что WebScoket может ограничиваться только этим. Конечно, его также можно использовать. В других сценариях для этого требуется, чтобы он мог обмениваться данными через не-HTTP-протоколы, поэтому WebSocket также принимает настраиваемый режим URI, чтобы гарантировать, что обмен данными может выполняться даже без HTTP.
ws и wss:
- ws-протокол: обычный запрос, занимающий тот же порт 80, что и HTTP
- протокол wss: безопасная передача на основе SSL, занимающая тот же порт 443, что и TLS.
Примечание. Некоторые промежуточные устройства HTTP иногда могут не понимать WebSocket, что приводит к различным проблемам, таким как: слепое обновление соединения, случайное изменение контента и т. д. WSS очень хорошо решает эту проблему, он устанавливает сквозной защищенный канал, который скрывает данные для промежуточного устройства, поэтому промежуточное устройство не может воспринимать данные и не может выполнять какую-то специальную обработку запроса.
3. Спецификация протокола WebSocket
Ниже приведен пример типичного запроса WebSocket типа «запрос-ответ»:
客户端到服务端:
GET / HTTP/1.1
Connection:Upgrade
Host:127.0.0.1:8088
Origin:null
Sec-WebSocket-Extensions:x-webkit-deflate-frame
Sec-WebSocket-Key:puVOuWb7rel6z2AVZBKnfw==
Sec-WebSocket-Version:13
Upgrade:websocket
服务端到客户端:
HTTP/1.1 101 Switching Protocols
Connection:Upgrade
Server:beetle websocket server
Upgrade:WebSocket
date: Thu, 10 May 2018 07:32:25 GMT
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:content-type
Sec-WebSocket-Accept:FCKgUr8c7OsDsLFeJTWrJw6WO8Q=
Мы видим, что между протоколом WebSocket и протоколом HTTP на первый взгляд нет большой разницы, но при более внимательном рассмотрении все же есть некоторые различия.На самом деле это HTTP-запрос рукопожатия, первый запрос и ответ: «Обновление: WebSocket» означает, что целью запроса является обновление протокола связи между клиентом и сервером с протокола HTTP на протокол WebSocket. Информация, запрашиваемая от клиента к серверу, содержит информацию заголовка, такую как «Sec-WebSocket-Extensions» и «Sec-WebSocket-Key». Это информация о рукопожатии, которую клиентский браузер должен предоставить серверу.Сервер анализирует информацию заголовка и генерирует 28-битный ключ безопасности на основе информации во время процесса рукопожатия и возвращает его клиенту, указывая, что сервер получает В ответ на запрос клиента соглашается на создание соединения WebSocket.
Когда рукопожатие прошло успешно, в это время установлено TCP-соединение, и клиент и сервер могут напрямую передавать данные через WebSocket. Однако серверу также необходимо определить, когда начинается и когда заканчивается запрос данных. В WebSocket, так как браузер и сервер уже поприветствовали друг друга, если отправляю контент в кодировке utf-8, если отправляю 0x00, значит начало пакета, а если отправляю 0xFF, значит конец пакет. Это решает проблему липких пакетов.
4. Совместимость
浏览器 支持情况
Chrome Supported in version 4+
Firefox Supported in version 4+
Internet Explorer Supported in version 10+
Opera Supported in version 10+
Safari Supported in version 5+
5. Сокет.IO
Проще говоря, Socket.IO является инкапсуляцией WebSocket и реализует серверный код WebSocket. Socket.IO инкапсулирует механизмы WebSocket и опроса (Polling) и другие методы связи в реальном времени в общие интерфейсы и реализует соответствующие коды этих механизмов реального времени на стороне сервера. Другими словами, WebSocket — это только подмножество Socket.IO для связи в реальном времени. Socket.IO упрощает API WebSocket и унифицирует API, который возвращает транспорт. Типы передачи включают в себя:
- WebSocket
- Flash Socket
- AJAX long-polling
- AJAX multipart streaming
- IFrame
- JSONP-опрос.
Давайте взглянем на базовый API Socket.IO на стороне сервера:
// 引入socke.io
const io = require('socket.io')(80)
// 监听客户端连接,回调函数会传递本次连接的socket
io.on('connection',function(socket))
// 给所有客户端广播消息
io.sockets.emit('String',data)
// 给指定的客户端发送消息
io.sockets.socket(socketid).emit('String', data)
// 监听客户端发送的信息
socket.on('String',function(data))
// 给该socket的客户端发送消息
socket.emit('String', data)
Кроме того, Socket.IO также предоставляет Node.JS API, который очень похож на клиентский API. Итак, давайте посмотрим на это в действии:
// socket-server.js
// 需要使用HTTP模块来启动服务器和Socket.IO
const http= require('http'),
const io= require('socket.io')
const server= http.createServer(function(req, res){
// 发送HTML的headers和message
res.writeHead(200,{ 'Content-Type': 'text/html' })
res.end('<p>Hello Socket.IO!<p>')
});
// 在8080端口启动服务器
server.listen(8080)
// 创建一个Socket.IO实例,并把它传递给服务器
const socket= io.listen(server)
// 添加一个连接监听器
socket.on('connection', function(client) {
// 连接成功,开始监听
client.on('message',function(event){
console.log('Received message from client!',event)
})
// 连接失败
client.on('disconnect',function(){
clearInterval(interval)
console.log('Server has disconnected')
})
})
Затем мы можем запустить этот файл:
node socket-server.js
Затем мы можем создать отправителя, который отправляет сообщения клиенту каждую секунду;
var interval= setInterval(function() {
client.send('This is a message from the server,hello world' + new Date().getTime());
},1000);
Примечание. Следует отметить, что если мы хотим использовать socket.IO на внешнем интерфейсе, нам необходимо загрузить это:
npm install socket.io-client --save
Затем снова подключитесь к сети:
import io from 'socket.io-client'
const socket = io('ws://localhost:8080')