美文网首页扣丁学堂PHP培训
扣丁学堂PHP培训浅谈PHP长连接实现与使用方法

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

作者: 994d14631d16 | 来源:发表于2018-07-30 13:12 被阅读3次

    本篇文章扣丁学堂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培训班供大家学习,不仅有时俱进的课程体系还有专业的老师授课,定能让你轻松学习,高薪就业。

    相关文章

      网友评论

        本文标题:扣丁学堂PHP培训浅谈PHP长连接实现与使用方法

        本文链接:https://www.haomeiwen.com/subject/ruzxvftx.html