Длинные опросы
Длинные опросы – это самый простой способ поддерживать постоянное соединение с сервером, не используя при этом никаких специфических протоколов (типа WebSocket или Server Sent Events).
Его очень легко реализовать, и он хорошо подходит для многих задач.
Частые опросы
Самый простой способ получать новую информацию от сервера – периодический опрос. То есть, регулярные запросы на сервер вида: «Привет, я здесь, у вас есть какая-нибудь информация для меня?». Например, раз в 10 секунд.
В ответ сервер, во-первых, помечает у себя, что клиент онлайн, а во-вторых посылает весь пакет сообщений, накопившихся к данному моменту.
Это работает, но есть и недостатки:
- Сообщения передаются с задержкой до 10 секунд (между запросами).
- Даже если сообщений нет, сервер «атакуется» запросами каждые 10 секунд, даже если пользователь переключился куда-нибудь или спит. С точки зрения производительности, это довольно большая нагрузка.
Так что, если речь идёт об очень маленьком сервисе, подход может оказаться жизнеспособным, но в целом он нуждается в улучшении.
Длинные опросы
«Длинные опросы» – гораздо лучший способ взаимодействия с сервером.
Они также очень просты в реализации, и сообщения доставляются без задержек.
Как это происходит:
- Запрос отправляется на сервер.
- Сервер не закрывает соединение, пока у него не возникнет сообщение для отсылки.
- Когда появляется сообщение – сервер отвечает на запрос, посылая его.
- Браузер немедленно делает новый запрос.
Для данного метода ситуация, когда браузер отправил запрос и удерживает соединение с сервером в ожидании ответа, является стандартной. Соединение прерывается только доставкой сообщений.
Если соединение будет потеряно, скажем, из-за сетевой ошибки, браузер немедленно посылает новый запрос.
Примерный код клиентской функции subscribe , которая реализует длинные опросы:
Функция subscribe() делает запрос, затем ожидает ответ, обрабатывает его и снова вызывает сама себя.
Архитектура сервера должна быть способна работать со многими ожидающими подключениями.
Некоторые серверные архитектуры запускают отдельный процесс для каждого соединения. Для большого количества соединений будет столько же процессов, и каждый процесс занимает значительный объём памяти. Так много соединений просто поглотят всю память.
Часто такая проблема возникает с бэкендом, написанными на PHP или Ruby, но технически дело не в языке, а в реализации. На большинстве современных языков можно написать подходящий сервер, но на некоторых это проще сделать.
Long Polling — Comparative and Sample Coded Expression
Of course, there is never a single truth during software development. We always come up with multiple options and try to determine which one suits us the best according to the requirements we have.
For example, there may be an exchange of information between “client” and “server” at times. However, the information needed by the client may not be ready there yet.
Sample Scenario
If you say what are such scenarios, the simplest example I can give is the messaging application…
Простая реализация long polling механизма на PHP
Итак, что же из себя представляет Long Polling?
Выглядит это примерно следующим образом:
1) Клиент отсылает на сервер обычный ajax-запрос
2) Сервер, вместо того, чтобы быстро обработать этот запрос и отправить ответ клиенту, запускает цикл, в каждой итерации которого следит за возникновением событий (другой клиент добавил запись или удалил).
3) При возникновении события сервер генерирует ответ и отсылает его клиенту, таким образом завершая запрос.
4) Клиент, получив ответ от сервера, запускает обработчик события и параллельно отправляет очередной «длинный» запрос серверу.
То есть всё довольно просто и понятно. Однако, при реализации возникает несколько вопросов, которые нужно решить.
Шаги к практике
В первую очередь возникает вопрос о том, как скрипты будут взаимодействовать друг с другом. Ведь на каждый запрос клиента к серверу создаётся независимая копия PHP-скрипта. То есть нужна какая-то общая память для хранения данных о событиях.
Традиционный вариант — запускается демон, который оперирует событиями и держит соединение с клиентами. Использование демона естественным образом решает проблему памяти. Клиенты обращаются для получения событий не на веб-сервер, а к демону. В то же время, клиент, инициализирующий событие, также сообщает демону, что произошло событие. И таким образом всё крутится в памяти этого демона. который вообще может быть написан на чём угодно.
Но нам, в виду шила в одном месте и желания обойтись без сторонних приложений, демон на чём угодно не подойдёт. А писать демона на PHP, на мой вкус, не слишком интересно. У хостера могут быть проблемы с изменением максимального времени работы скрипта, а ещё продумывать интерфейсы взаимодействия клиентов с этим демоном… Нет, мы пойдём другим путём.
А остаётся только решить, как реализовать общую память в самом PHP. В голову приходят варианты хранения событий в файлах и БД, но хочется-то, чтобы всё было поближе — в памяти. Memcache нам, увы недоступен, а что тогда делать? А есть в php такое понятие как shared memory, точнее понятие-то не является особенностью этого языка, но нам дают возможность этим пользоваться. Механизмы этой технологии позволяют нам создать ячейку в оперативной памяти и использовать её в своих целях. Вот её я и буду использовать.
Практика
Попробуем представить интерфейс класса, который будет реализовывать нужный нам функционал.
Какие нужны методы?
1) Естественно, метод «прослушки», который будет вызываться, когда клиенты будут посылать polling-запросы, и следить за возникающими событиями. Я назвал этот метод listen.
2) Кроме того нам понадобится метод, который будет создавать событие. Этот метод носит имя push.
3) Вполне вероятно, что мы захотим обработать данные о событии, прежде чем отправить результат клиенту. Поэтому я добавил метод, который регистрирует событие и связывает с ним обработчик. Называется метод registerEvent.
В итоге получаем такой интерфейс класса:
Несколько примечаний:
1) В методе registerEvent поддерживается только по одному обработчику на событие по причине того, что возвращаемое обработчиком значение возвращается клиенту как данные события. В одном обработчике можно вызвать несколько функций и из результата их работы собрать ответ клиенту. Впрочем переделать код для поддержки нескольких обработчиков можно без особых затруднений.
2) В методе listen используется параметр lastQueryTime, который позволяет обработать события, возникшие раньше, чем поступил запрос на прослушку. Это может пригодиться когда нагрузка на сеть высока и между завершением одного polling-запроса от клиента и началом другого может пройти заметный промежуток времени, в который возникают события.
3) В приведённом коде не учитывается одновременный доступ к памяти. А вообще. для более надёжной работы желательно использовать семафоры.
4) В методе listen используется вызов функции sleep(1). Это нужно для того, чтобы уменьшить количество холостых итераций. Частоты обновления раз в секунду вполне достаточно для имитации реалтайма.
Ну и на клиенте всё также предельно просто. Нам нужен метод, который будет посылать polling-запрос серверу, ждать ответ, запускать обработчики событий и заново посылать запрос. Ну и метод, регистрирующий сами обработчики событий.
Исходники:
Описанный класс Polling на PHP.
Если кому-нибудь понадобится, приведу в порядок и выложу клиентскую часть.
Long polling что это
In this article, we will know about the Polling concept, along with knowing the different types of Polling available, with an understanding of the basic differences between them & the related code examples.
Polling simply means checking for new data over a fixed interval of time by making API calls at regular intervals to the server. It is used to get real-time updates in applications. There are many applications that need real-time data and polling is a life savior for those applications.
Different types of Polling:
- Short Polling: In a short polling client requests data from the server and the server will return the response if it is available and if it is not available then it returns an empty response. This process will be repeated at regular intervals.
We will understand short polling with the help of an example, where will use AJAX to understand Short Polling, although, we can also use normal HTTP requests.
Steps for short Polling using AJAX are given below:
- create a new XMLHttpRequest.
- Use the open() method of XMLHttpRequest to specify the request.
- Use send() method of XMLHttpRequest to send a request to the server.
- Use the “onreadystatechange” property of XMLHttpRequest to define a function that will help us to use our response at any place.
- Use responseText inside that function to show your data anywhere on the webpage.
- Place this entire request and response in setInterval by specifying an interval.
- Then place that setInterval inside a function that will be called on the button click.
Example 1: In this example, we took the server file as data.json which contains some data.
data.json:
Output:
Although, there are a few problems with short polling, i.e., the frequency of polling can cause an unacceptable burden on the network, the server, or both, when the acceptable latency is low, in general.
Long Polling: In Short polling, there was a problem that if the response is not available then the server returns an empty response.
So, In long polling, this problem got solved. Here, in long polling, the client sends a request to the server and if the response is not available then the server will hold the request till the response gets available, & after the availability of the response, the server will send the response back. After getting a response, again the request will be made either immediately or after some period of time and this process will repeat again and again. In simple words, the client will always be in the live connection to the server.
Example 2: In this example, we will understand long polling, where we will use AJAX for understanding long polling, although, we can use normal HTTP requests as well. The steps are described below: