>  기사  >  백엔드 개발  >  PHP는 긴 연결 방법을 구현합니다.

PHP는 긴 연결 방법을 구현합니다.

小云云
小云云원래의
2018-03-21 11:50:004620검색

서버 측에서 연결을 유지하고 즉시 반환하지 않습니다. 이것이 긴 연결 기술의 원칙입니다. 이 기사에서는 주로 PHP에서 긴 연결을 구현하는 방법을 공유하기를 바랍니다. 모두에게 도움이 될 수 있습니다.

장기 연결 기술의 핵심은 HTTP 요청을 보류하고 새 데이터가 있을 때까지 요청에 응답하지 않는 것입니다. 그러면 클라이언트가 자동으로 장기 연결 요청을 다시 시작합니다.

그렇다면 요청을 어떻게 보류합니까? 서버 측 코드는 다음과 같습니다.

set_time_limit(0);  //这句很重要, 不至于运行超时while (true) 
、{    if (hasNewMessage()) 
{        echo json_encode(getNewMessage());        break;
    }
    usleep(100000);      //避免太过频繁的查询}


예, 즉시 반환되지 않도록 요청을 보류하는 루프를 통해 구현됩니다. 그런 다음 새 데이터를 쿼리한 후에만 요청에 응답합니다. 클라이언트가 데이터를 처리하고 긴 연결 요청을 다시 시작합니다.

클라이언트 코드는 다음과 같습니다

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

간단한 채팅방

긴 연결을 통해 간단한 웹 채팅방을 개발할 수 있습니다

다음으로 개발합니다. Redis를 통한 간단한 채팅방 웹 채팅방

  1. 각 클라이언트가 긴 연결을 시작하면 서버 측에 사용자에 해당하는 메시지 대기열이 생성됩니다. 그런 다음 새로운 데이터가 있는지 모니터링하고 데이터를 반환합니다. 처리를 위해 클라이언트에 연결을 요청하고 다시 긴 연결을 시작합니다.

  2. 각 클라이언트가 메시지를 시작하면 메시지 대기열이 브로드캐스트됩니다.

다음은 코드 조각입니다.

<?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[&#39;type&#39;]) {            case &#39;unicast&#39;:     //单播
                $this->unicast($data[&#39;target&#39;], $data[&#39;data&#39;], $data[&#39;resource&#39;]);                break;            case &#39;multicast&#39;:       //组播
                foreach ($data[&#39;target&#39;] as $target) {                    $this->unicast($target, $data[&#39;data&#39;], $data[&#39;resource&#39;]);
                }                break;            case &#39;broadcast&#39;:       //广播
                foreach ($this->redisQueue->setQueueName(&#39;connections&#39;) as $target) {                    $this->unicast($target, $data[&#39;data&#39;], $data[&#39;resource&#39;]);
                }                break;
        }        $this->fire(&#39;message&#39;);
    }    public function unicast($target, $message, $resource = &#39;system&#39;)
    {
        $redis_queue = new RedisQueue();        $redis_queue->setQueueName($target)->push($resource . &#39;:&#39; . $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(&#39;action&#39;) == &#39;getMessage&#39;) {                if ($this->hasMessage($data->get(&#39;target&#39;))) {                    $this->response->setData([                        &#39;state&#39; => &#39;ok&#39;,                        &#39;message&#39; => &#39;获取成功&#39;,                        &#39;data&#39; => $this->getMessage($data->get(&#39;target&#39;))
                    ]);                    $this->response->send();                    break;
                }
            } elseif ($data->get(&#39;action&#39;) == &#39;connect&#39;) {                $exist = false;                foreach ($this->redisQueue->setQueueName(&#39;connections&#39;) as $connection) {                    if ($connection == $data->get(&#39;data&#39;)) {                        $exist = true;
                    }
                }                if (! $exist) {                    $this->redisQueue->setQueueName(&#39;connections&#39;)->push($data->get(&#39;data&#39;));   
                }               
                $this->fire(&#39;connect&#39;);                break;
            }
            usleep(100000);
        }
    }
}

는 오픈 소스입니다. 소스 코드는 github

긴 연결을 기반으로 개발된 간단한 웹 버전입니다. 채팅방에서는 긴 연결을 사용하면 너무 빈번한 폴링을 피할 수 있습니다. 그러나 서버에서 긴 연결을 유지하는 것도 동시성이 큰 경우 성능이 이상적이지 않습니다. . 소규모 애플리케이션에 사용하는 것이 고려될 수 있습니다. 클라이언트는 html5 websocket 프로토콜을 사용하고 서버는 swoole을 사용하는 것이 더 좋습니다.

관련 권장 사항:

PHP 소켓에서 긴 연결을 구현하는 방법

길고 짧은 http 연결의 원리에 대한 간략한 분석

PHP 중장거리 연결

실현

위 내용은 PHP는 긴 연결 방법을 구현합니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.