1. Что такое веб-сокет?
WebSocketЭто сетевой коммуникационный протокол, необходимый для многих дополнительных функций. Любой, кто новичок в WebSockets, задаст один и тот же вопрос: у нас уже есть протокол HTTP, зачем нам еще один протокол? Какую пользу это может принести? Ответ прост, потому что протокол HTTP имеет изъян: связь может инициировать только клиент. Например, если мы хотим узнать сегодняшнюю погоду, клиент может только отправить запрос на сервер, а сервер возвращает результат запроса. Протокол HTTP не может позволить серверу активно передавать информацию клиенту. Характеристики этого одностороннего запроса обречены быть очень неприятными для клиента, чтобы узнать, есть ли у сервера непрерывные изменения состояния. мы можем использовать только"опрос": время от времени отправляется запрос, чтобы узнать, есть ли на сервере новая информация. Самый типичный сценарий — чат. Опрос неэффективен и тратит ресурсы впустую (потому что вам нужно постоянно подключаться, иначе HTTP-соединение всегда открыто). Поэтому инженеры задумались, а есть ли способ лучше. Так был изобретен WebSocket.
Его самая большая особенность заключается в том, что сервер может активно передавать информацию клиенту, а клиент также может активно отправлять информацию серверу.Это настоящий двусторонний равноправный диалог, который принадлежиттехнология push сервератипа.
Другие функции включают в себя:
(1) Основываясь на протоколе TCP, реализация на стороне сервера относительно проста.
(2) Хорошая совместимость с протоколом HTTP. Порты по умолчанию также 80 и 443, а протокол HTTP используется на этапе рукопожатия, поэтому его нелегко экранировать во время рукопожатия, и он может проходить через различные прокси-серверы HTTP.
(3) Формат данных относительно легкий, производительность невелика, а связь эффективна.
(4) Можно отправлять текст, а также двоичные данные.
(5) Нет ограничений на одно и то же происхождение, и клиент может связываться с любым сервером.
(6) идентификатор протоколаws
(если зашифровано,wss
), URL-адрес сервера — это URL-адрес.
2. Простой пример WebSocket
var ws = new WebSocket("ws://echo.websocket.org");
ws.onopen = function(evt) {
console.log("Connection open ...");
ws.send("Hello WebSockets!");
};
ws.onmessage = function(evt) {
console.log( "Received Message: " + evt.data);
ws.close();
};
ws.onclose = function(evt) {
console.log("Connection closed.");
}
3. Введение в распространенные API WebSocket
-
конструктор веб-сокетов
let ws = new WebSocket('ws://localhost:8080');
После выполнения вышеуказанного оператора клиент подключится к серверу.
-
Состояние веб-сокета (readyState)
Свойство readyState возвращает текущее состояние экземпляра объекта, всего существует четыре состояния.
CONNECTING:值为0, 正在连接 OPEN:值为1,连接成功 CLOSING:值为2,连接正在关闭 CLOSED:值为3,连接已经关闭
-
websocket.onopen (функция обратного вызова после успешного подключения)
экземпляр объекта
onopen
Атрибут для указания функции обратного вызова после успешного подключения.ws.onopen = function () { ws.send('Hello Server!'); }
Если вы хотите указать несколько функций обратного вызова, вы можете использовать
addEventListener
метод.ws.addEventListener('open', function (event) { ws.send('Hello Server!'); });
-
websocket.onclose (метод вызывается после закрытия)
экземпляр объекта
onclose
Атрибут для указания функции обратного вызова после закрытия соединения.ws.onclose = function(event) { console.log('onclose') }
Если вы хотите указать несколько функций обратного вызова, вы можете использовать
addEventListener
метод.ws.addEventListener("close", function(event) { console.log('onclose') });
-
websocket.onmessage (функция обратного вызова после получения данных сервера)
ws.onmessage = function(event) { // 获取数据event.data var data = event.data; // 处理数据 };
-
websocket.send (отправить данные на сервер)
ws.send('your message')
-
websocket.onerror (метод вызывается при сообщении об ошибке)
ws.onerror = function(event) { // handle error event };
4.Пребят сердцебиение
Websocket – это длинная связь между интерфейсом и сервером. Интерфейс и сервер также могут не установить соединение из-за некоторых ситуаций, и между ними нет напоминания об обратной связи. Поэтому, чтобы обеспечить устойчивость и стабильность соединения, появилось переподключение через веб-сокет. При использовании собственного веб-сокета, если сеть устройства отключена, любое событие веб-сокета не будет инициировано немедленно, и внешний интерфейс не сможет узнать, было ли разорвано текущее соединение. В это время, если вызывается метод websocket.send, браузер обнаружит, что ссылка отключена, и вызовет функцию onclose немедленно или через определенный период времени (разные браузеры или версии браузеров могут вести себя по-разному). Внутренняя служба веб-сокетов также может быть ненормальной, что приводит к отключению соединения. В это время внешний интерфейс не получает уведомления об отключении. Поэтому внешний интерфейс должен регулярно отправлять сообщение пульса. -end получает сообщение типа ping и немедленно возвращает сообщение pong, чтобы сообщить, что внешнее соединение нормальное. Если сообщение pong не получено в течение определенного периода времени, это означает, что соединение не является нормальным, и внешний интерфейс выполнит переподключение. Чтобы решить две вышеупомянутые проблемы, внешний интерфейс используется в качестве активной стороны, и сообщения ping регулярно отправляются для обнаружения проблем с сетью, внешним и внутренним подключением. После обнаружения исключения внешний интерфейс продолжает выполнять логику переподключения до тех пор, пока переподключение не будет успешным.
Общая функция обнаружения сердцебиения:
// 心跳检测, 每隔一段时间检测连接状态,如果处于连接中,就向server端主动发送消息,来重置server端与客户端的最大连接时间,如果已经断开了,发起重连。
let heartCheck = {
// 心跳,比server端设置的连接时间稍微小一点,在接近断开的情况下以通信的方式去重置连接时间。
timeout: 100000,
serverTimeoutObj: null,
reset: function() {
clearTimeout(this.serverTimeoutObj)
return this
},
start: function() {
this.serverTimeoutObj = window.setInterval(() => {
if (websocket.readyState === 1) {
websocket.send('ping')
} else {
window.clearTimeout(this.serverTimeoutObj)
// 处理逻辑:重连或者其他
}
}, this.timeout)
}
}
5. Пример полного кода WebSocket
function newWebSocket(option) {
console.log('new webSocket.....')
let websocket = null
// 判断当前环境是否支持websocket
if (window.WebSocket) {
if (!websocket) {
websocket = new WebSocket('你的请求地址')
}
} else {
console.log('not support websocket')
}
// 连接成功建立的回调方法
websocket.onopen = function(e) {
// 成功建立连接后,重置心跳检测
heartCheck.reset().start()
console.log('connected successfully')
}
// 连接发生错误,连接错误时会继续尝试发起连接
websocket.onerror = function() {
console.log(`onerror`)
newWebSocket()
}
// 接受到消息的回调方法
websocket.onmessage = function(e) {
console.log('onmessage', e.data)
var message = e.data
if (message) {
// 执行接收到消息的操作
if (option != undefined) {
// 执行传入对象的方法,传出消息
option.onmessage(message)
}
}
}
// 接受到服务端关闭连接时的回调方法
websocket.onclose = function() {
console.log('onclose')
}
// 监听窗口事件,当窗口关闭时,主动断开websocket连接,防止连接没断开就关闭窗口,server端报错
window.onbeforeunload = () => {
return websocket.close()
}
// 心跳检测, 每隔一段时间检测连接状态,如果处于连接中,就向server端主动发送消息,来重置server端与客户端的最大连接时间,如果已经断开了,发起重连。
var heartCheck = {
// 心跳,比server端设置的连接时间稍微小一点,在接近断开的情况下以通信的方式去重置连接时间。
timeout: 100000,
serverTimeoutObj: null,
reset: function() {
clearTimeout(this.serverTimeoutObj)
return this
},
start: function() {
this.serverTimeoutObj = window.setInterval(() => {
if (websocket.readyState === 1) {
websocket.send('ping')
} else {
console.log('websocket stop', websocket.readyState)
window.clearTimeout(this.serverTimeoutObj)
newWebSocket(option)
}
}, this.timeout)
}
}
return websocket
}