扣丁学堂PHP培训

扣丁学堂PHP培训浅谈PHP长连接实现与使用方法

2018-07-30  本文已影响3人  994d14631d16

本篇文章扣丁学堂PHP培训小编和大家分享一下PHP长连接实现与使用方法,对PHP开发感兴趣的小伙伴下面就随着小编一起来看一下吧。

扣丁学堂PHP培训

长连接技术(Long Polling):

在服务器端hold住一个连接,不立即返回,直到有数据才返回,这就是长连接技术的原理,长连接技术的关键在于hold住一个HTTP请求,直到有新数据时才响应请求,然后客户端再次自动发起长连接请求。

那怎么样hold住一个请求呢?服务器端的代码可能看起来像这样的:

set_time_limit(0); //这句很重要, 不至于运行超时

while (true) {

  if (hasNewMessage()) {

    echo json_encode(getNewMessage());

    break;

  }

  usleep(100000);   //避免太过频繁的查询

}

没错,就是通过循环来实现hold住一个请求, 不至于立即返回. 查询到有新数据之后才响应请求. 然后客户端处理数据后,再次发起长连接请求。

客户端的代码是像这样的:

  (function longPolling() {

    $.ajax({

      'url': 'server.php',

      'data': data,

      'dataType': 'json',

      'success': function(data) {

        processData(data);

        longPolling();

      },

      'error': function(data) {

        longPolling();

      }

    });

  })();

一个简易的聊天室:

通过长连接, 我们可以开发一个简易的web聊天室,下面, 我们通过redis开发一个简易的web聊天室:

1、每一个客户端发起长连接时, 在服务器端生成一个消息队列, 对应该用户. 然后监听有无新数据, 有则返回数据到客户端进行处理, 并再起发起长连接请求。

2、每一个客户端发起消息时, 进行消息队列的广播

下面是代码片段:

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':   //单播

        $this->unicast($data['target'], $data['data'], $data['resource']);

        break;

      case 'multicast':    //组播

        foreach ($data['target'] as $target) {

          $this->unicast($target, $data['data'], $data['resource']);

        }

        break;

      case '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' => '获取成功',

            '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);

    }

  }

}

长连接避免了过于频繁的轮询. 但服务器维持一个长连接也有额外的资源消耗. 大并发时性能不理想. 在小型应用里面可以考虑使用,更建议客户端使用html5的websocket协议, 服务器端使用swoole。

以上就是扣丁学堂PHP在线学习小编给大家分享的PHP长连接实现与使用方法详解,希望对小伙伴们有所帮助,想要了解更多内容的小伙伴可以登录扣丁学堂官网咨询。扣丁学堂有专业的PHP培训班供大家学习,不仅有时俱进的课程体系还有专业的老师授课,定能让你轻松学习,高薪就业。

上一篇下一篇

猜你喜欢

热点阅读