Comments 9
Очень радуюсь каждому проекту про двустороннюю связь клиента с сервером, спасибо за статью, читал с интересом.
Но вот про отношение к пользовательской батарее неприятно было читать. И ни у кого в моем окружении аккумулятор с 0 до 100 за 15 минут не заряжается. Как быть? =)
Можно сказать появились тепличные условия для восхождения WebSocket и почему бы и нет.
Далеко не все так просто. Не стоит сильно закладываться на Websocket, потому как:
Никто не отменял кратковременные потери связи. Поэтому придется так или иначе на клиенте придется поверх имплементировать или пользовать протокол с реконнектом типа MQTT, что усложнит ситуацию вцелом и в итоге не сильно будет отличаться от лонг поллинга.
При отсутствии треффика соединение автоматически не закрывается ни на одной из сторон. Получается так, что клиент уже отвалился, а сервер еще "держит" его соединение. То же самое с клиентом -- соединение еще открыто, но сервер уже его давно дропнул. Чтобы это решить, люди делают периодический heartbeat, но он сразу жрет батарею и вносит определенную задержку.
Когда соединение проходит через промежуточный роутер с маскарадингом или через прокси, они как правило убивают коннекшн при отсутствии треффика. И одному Админу известно во сколько выставлен таймаут в каждом конкретном случае. Поэтому хардбит придется делать часто: от 30 секунд до 1 минуты.
Было замечено с некоторыми моделями мобильных девайсов, что они могут аккумулировать которкие сообщения перед отсылкой их по вебсокету (до 20 секунд). А самому выставить параметры сокета, типа TcpNoDelay, нет никакой возможности.
Поэтому как протокол вебсокет хорош для приложений с интенсивным обменом траффика, но в сыром виде не совсем подходит для кейсов с обменом редкими сообщениями.
Никто не отменял кратковременные потери связи
В вот то и дело, что сейчас потерь вообще не наблюдается и даже если когда-нибудь потеряется связь, то реконнект будет мгновенный
При отсутствии треффика соединение автоматически не закрывается ни на одной из сторон.
Согласно спецификации WebSocket есть специальное событие onclose, который в нашем случае прописан в коде и выполняется всегда при потере коннекта, а в случае клиента событие onclose возникает при очередном опросе ping-pong - что неплохо и на самом деле ping-pong ничего не кушает. Например, я на бюджетном Samsung Galaxy A51 без зарядки могу играть 3-4 часа в PUBG - а там сплошной трафик и выставлено максимальное качество графики со всеми тенями =)
Когда соединение проходит через промежуточный роутер с маскарадингом или через прокси, они как правило убивают коннекшн при отсутствии треффика
Во всех роутерах по умолчанию с завода нет ограничений, но если мы говорим о телефонах, то там обычно прямая связь
Было замечено с некоторыми моделями мобильных девайсов, что они могут аккумулировать которкие сообщения перед отсылкой их по вебсокету (до 20 секунд)
Ну это скорее всего особенность реализации библиотеки WebSocket =)
В вот то и дело, что сейчас потерь вообще не наблюдается и даже если когда-нибудь потеряется связь, то реконнект будет мгновенный
Мгновенный или нет, но во время реконнекта может пропасть событие. Поэтому сервер должен хранить последние сообщения в очереди, а клиент при реконнекте должен сказать номер последнего полученного, чтобы тот сервер отослал все новые.
Согласно спецификации WebSocket есть специальное событие onclose, который в нашем случае прописан в коде и выполняется всегда при потере коннекта
При потере коннекта onclose может не вызваться вообще, так уж устроен tcp. Если у сокета отправочный буфер пустой, но он никогда и не закроется. Чтобы сокет закрылся, нужно обязательно через него что-то отправить, и то это произойдет не сразу, а лишь по таймауту на ACK и истечению повторов.
Кстати, было замечено, что у мобильных стеков tcp-таймауты на вебсокет выкручены на максимум, из-за чего возникает ощущение неразрывности коннекшна. Он тупо лагает, но не рвется. Приходится поверх въявную реализовывать свой механизм таймаутов на пинг-понгах.
ping-pong - что неплохо и на самом деле ping-pong ничего не кушает
Это для foreground приложений. А если приложение должно постоянно находиться в background и просыпаться лишь по приходу месседжа, то 3-4 часа -- это отвратительно. Постоянный пинг не даст телефону уйти в спящий режим и снизить энергопотребление.
Во всех роутерах по умолчанию с завода нет ограничений
Мы говорим о gateway-ях, корпоративных роутерах или проксях. Особенно последние безбожно дропают соединения без треффика по таймауту.
Мгновенный или нет, но во время реконнекта может пропасть событие
Хранить необязательно, если используешь принцип commit'a
При потере коннекта onclose может не вызваться вообще
Достаточно на сервере закрыть, что и делаем, а браузер можно в пекло =)
постоянно находиться в background и просыпаться лишь по приходу месседжа, то 3-4 часа -- это отвратительно
Энергопотребление и особенно в режиме экономии у телефонов последних пары лет потрясает, при этом, чаще в Telegram сообщения падают, чем происходит ping-pong, так что всё прекрасно
корпоративных роутерах или проксях. Особенно последние безбожно дропают соединения без треффика по таймауту.
Практически у всех в телефоне есть Интернет от мобильного оператора, т.е. проблем нет
Если так боитесь WebSocket, то посмотрите на десятки миллионов людей, что используют WebSocket в мобильных приложениях при заказе такси, доставке еды, в социальных сетях, покупке и продаже акций, практически во всех компьютерных играх! и ни один из них не жалуется на проблемы со связью =)
Я не боюсь Websocket, я использую его для онлайн шахмат в Телеграмме https://t.me/gamefactorybot :) Просто хотел поделиться своим опытом, согласно которому не все так просто чтобы сделать устойчивый коннект и гарантированную доставку месседжей. Основная проблема в том, что если что-то хорошо работает на ваших девайсах, это не означает, что то же самое будет также стабильно работать у Васи. Когда начала расти аудитория, было много комплейнов от юзеров. Пришлось вставлять средства мониторинга коннекшна в сам клиент и глубже изучать тему.
Reactive Spring Cloud Gateway: конвейер WebSocket в Restful и обратно