Implementation and Application of PHP Long Connection

  • 2021-09-11 19:44:11
  • OfStack

This paper describes the implementation and use of PHP long connection with examples. Share it for your reference, as follows:

Long Connection Technology (Long Polling)

On the server side, hold lives a connection, does not return immediately, and does not return until there is data, which is the principle of long connection technology

The key of long connection technology is that hold holds an HTTP request, and then responds to the request until there is new data, and then the client automatically initiates the long connection request again.

So how about hold live a request? Server-side code might look like this


set_time_limit(0); // This sentence is very important ,  Do not run out of time 
while (true) {
  if (hasNewMessage()) {
    echo json_encode(getNewMessage());
    break;
  }
  usleep(100000);   // Avoid too frequent queries 
}

Yes, it is through the loop to achieve hold live a request, not immediately return. Query to have new data before responding to the request. Then the client processing the data, and then initiate a long connection request.

The client-side code looks like this


<script type="text/javascript">
  (function longPolling() {
    $.ajax({
      'url': 'server.php',
      'data': data,
      'dataType': 'json',
      'success': function(data) {
        processData(data);
        longPolling();
      },
      'error': function(data) {
        longPolling();
      }
    });
  })();
</script>

1 simple chat room

With a long connection, we can develop a simple web chat room

Next, we will develop a simple web chat room through redis

1. When each client initiates a long connection, a message queue is generated at the server end, which corresponds to the user, then monitors whether there is new data, returns the data to the client end for processing, and initiates the long connection request again.

2. When every client initiates a message, broadcast the message queue.

Here's the code snippet:


<?php
namespace church\LongPolling;
use Closure;
use church\LongPolling\Queue\RedisQueue;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
class Server
{
  public $event = [];
  public $redisQueue = null;
  public $request = null;
  public $response = null;
  public function __construct()
  {
    $this->redisQueue = new RedisQueue();
    $this->request = Request::createFromGlobals();
    $this->response = new JsonResponse();
  }
  public function on($event, Closure $closure)
  {
    if (is_callable($closure)) {
      $this->event[$event][] = $closure;
    }
  }
  public function fire($event)
  {
    if (isset($this->event[$event])) {
      foreach ($this->event[$event] as $callback) {
        call_user_func($callback, $this);
      }
    }
  }
  public function sendMessage($data)
  {
    switch ($data['type']) {
      case 'unicast':   // Unicast 
        $this->unicast($data['target'], $data['data'], $data['resource']);
        break;
      case 'multicast':    // Multicast 
        foreach ($data['target'] as $target) {
          $this->unicast($target, $data['data'], $data['resource']);
        }
        break;
      case 'broadcast':    // Broadcast 
        foreach ($this->redisQueue->setQueueName('connections') as $target) {
          $this->unicast($target, $data['data'], $data['resource']);
        }
        break;
    }
    $this->fire('message');
  }
  public function unicast($target, $message, $resource = 'system')
  {
    $redis_queue = new RedisQueue();
    $redis_queue->setQueueName($target)->push($resource . ':' . $message);
  }
  public function getMessage($target)
  {
    return $this->redisQueue->setQueueName($target)->pop();
  }
  public function hasMessage($target)
  {
    return count($this->redisQueue->setQueueName($target));
  }
  public function run()
  {
    $data = $this->request->request;
    while (true) {
      if ($data->get('action') == 'getMessage') {
        if ($this->hasMessage($data->get('target'))) {
          $this->response->setData([
            'state' => 'ok',
            'message' => ' Achieve success ',
            'data' => $this->getMessage($data->get('target'))
          ]);
          $this->response->send();
          break;
        }
      } elseif ($data->get('action') == 'connect') {
        $exist = false;
        foreach ($this->redisQueue->setQueueName('connections') as $connection) {
          if ($connection == $data->get('data')) {
            $exist = true;
          }
        }
        if (! $exist) {
          $this->redisQueue->setQueueName('connections')->push($data->get('data'));
        }
        $this->fire('connect');
        break;
      }
      usleep(100000);
    }
  }
}

Long connections avoid too frequent polling. However, maintaining a long connection on the server also has extra resource consumption. Performance is not ideal when it is large concurrent. You can consider using it in small applications

It is recommended that the client use the websocket protocol of html5 and the server use swoole.

For swoole, you can see official website: https://www.swoole.com/

For more readers interested in PHP related content, please check the topics on this site: "php socket Usage Summary", "php String Usage Summary", "PHP Mathematical Operation Skills Summary", "php Object-Oriented Programming Introduction Course", "PHP Array (Array) Operation Skills Complete Book", "PHP Data Structure and Algorithm Course", "php Programming Algorithm Summary" and "PHP Network Programming Skills Summary"

I hope this article is helpful to everyone's PHP programming.


Related articles: