📜 ⬆️ ⬇️

Simple implementation of the long polling mechanism in PHP

Nowadays, the use of the Comet technology is quite popular, “when a permanent HTTP connection allows the web server to send (push) data to the browser, without any additional request from the browser,” according to Wikipedia.
There are many different implementations of this technology, but now I want to dwell on one of them, which is called Long Polling. In the article I will understand what it is and what it is eaten with.
Well, for those who know that it may be interesting to look at an implementation that does not use third-party software for their work - only PHP. Why is this necessary if there are special comet-servers that can withstand much higher loads than the PHP script? This can be useful if you need to make a small project without high loads, and on the hosting do not allow to put third-party software. Well, if I had to implement this functionality within one task, where it was just impossible to use third-party applications, then why not share it.

Theory

So what is Long Polling?
It looks something like this:
1) The client sends a normal ajax request to the server
2) The server, instead of quickly processing this request and sending a response to the client, starts a cycle, in each iteration of which it monitors the occurrence of events (another client added a record or deleted it).
3) When an event occurs, the server generates a response and sends it to the client, thus completing the request.
4) The client, having received a response from the server, starts the event handler and simultaneously sends the next “long” request to the server.

That is, everything is quite simple and clear. However, the implementation raises several issues that need to be addressed.

Steps to practice

')
The first question is how the scripts will interact with each other. After all, for each client request to the server, an independent copy of the PHP-script is created. That is, you need some kind of shared memory to store event data.
The traditional option is to start a daemon that handles events and keeps the connection with clients. Using a daemon naturally solves the memory problem. Clients access to receive events not on a web server, but on a daemon. At the same time, the client initiating the event also informs the daemon that an event has occurred. And so everything is spinning in the memory of this demon. which generally can be written on anything.
But we, in view of sewed in one place and the desire to do without third-party applications, the demon on anything does not fit. And writing a PHP daemon, for my taste, is not very interesting. The hoster may have problems with changing the maximum time of the script, and also think about the interfaces of the interaction of clients with this demon ... No, we will go the other way.
And it remains only to decide how to implement shared memory in PHP itself. The options of storing events in files and databases come to mind, but I want everything to be closer - in memory. Memcache to us, alas, is unavailable, and then what to do? And in php there is such a thing as shared memory, more precisely, the concept is not a feature of this language, but we are allowed to use it. The mechanisms of this technology allow us to create a cell in memory and use it for our own purposes. Here I will use it.

Practice

Let's try to provide an interface to the class that will implement the functionality we need.
What methods are needed?
1) Naturally, the "wiretapping" method, which will be called when clients send polling requests, and monitor the events that occur. I called this method listen .
2) In addition, we need a method that will create an event. This method is named push .
3) It is likely that we will want to process the event data before sending the result to the client. Therefore, I added a method that registers an event and associates a handler with it. The registerEvent method is called.

As a result, we get the following class interface:
class Polling { /** *   * @param string $event   * @param array $data   */ public function push($event, $data = null); /** * ""  .      max_execution_time * @param int $lastQueryTime      "". *    ,      ,  *  .   ,        * @return array         */ public function listen($lastQueryTime = null); /** *     .      . * @param string $event   * @param callback $callback - */ public function registerEvent($event, $callback); } 


A few notes:
1) In the registerEvent method, only one handler per event is supported, because the return value of the handler is returned to the client as event data. In one handler, you can call several functions and collect the response from the result of their work to the client. However, it is possible to alter the code to support multiple handlers without much difficulty.
2) In the listen method, the lastQueryTime parameter is used , which allows you to handle events that occurred before the listen request was received. This can be useful when the load on the network is high and between the completion of one polling request from the client and the start of another, a noticeable period of time may elapse in which events occur.
3) The above code does not take into account simultaneous access to the memory. But in general. for more reliable operation it is desirable to use semaphores.
4) In the listen method, the function call sleep (1) is used . This is necessary in order to reduce the number of idle iterations. The update rate once per second is quite enough to simulate realtime.

Well, everything is also extremely simple on the client. We need a method that will send a polling request to the server, wait for a response, start event handlers, and resubmit the request. Well and the method registering event handlers.

Sources:
The described Polling class in PHP .
If someone needs, I will put in order and lay out the client part.

Source: https://habr.com/ru/post/128535/


All Articles