php長接続を実現
13553 ワード
ロングコネクション技術(Long Polling)
サーバ側で1つの接続をholdし、すぐに返さず、データがあるまで返さないのが長接続技術の原理です.
長接続技術の鍵は、新しいデータがあるまでHTTP要求に応答し、クライアントが再び長接続要求を自動的に開始することにある.
では、どうやってお願いをしますか?サーバ側のコードはこのように見えるかもしれません
そう、すぐに戻ることなく、ループによってholdを実現する要求である.要求に応答するには、新しいデータがクエリされる.その後、クライアントがデータを処理する後、再び長接続要求を開始する.
クライアントのコードはこのようなものです
簡易なチャットルーム
長い接続で簡単なWebチャットルームを開発できます
次に、redisを通じて簡単なwebチャットルームを開発します.クライアントごとに長い接続が開始すると、サーバ側でメッセージキューが生成され、当該ユーザに対して.その後、新しいデータの有無を傍受する、ある場合はデータをクライアントに返す処理を行い、長い接続要求を再開する. クライアント毎にメッセージが開始すると、メッセージキューのブロードキャストが行われる.
次はコードクリップです.
ソースコードをgithubにオープンソースしました
長接続に基づいて開発されたweb版簡易チャットルーム
長い接続は頻繁なポーリングを避ける.しかし、サーバが長い接続を維持することは、追加のリソース消費もある.大同時時の性能は理想的ではない.スモールアプリケーションでの使用も考えられます
クライアントはhtml 5のwebsocketプロトコルを使用することを提案し、サーバ側はswooleを使用する.
swooleについては、ここを突いてもいいです.
サーバ側で1つの接続をholdし、すぐに返さず、データがあるまで返さないのが長接続技術の原理です.
長接続技術の鍵は、新しいデータがあるまでHTTP要求に応答し、クライアントが再び長接続要求を自動的に開始することにある.
では、どうやってお願いをしますか?サーバ側のコードはこのように見えるかもしれません
set_time_limit(0); // ,
while (true) {
if (hasNewMessage()) {
echo json_encode(getNewMessage());
break;
}
usleep(100000); //
}
そう、すぐに戻ることなく、ループによってholdを実現する要求である.要求に応答するには、新しいデータがクエリされる.その後、クライアントがデータを処理する後、再び長接続要求を開始する.
クライアントのコードはこのようなものです
<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>
簡易なチャットルーム
長い接続で簡単なWebチャットルームを開発できます
次に、redisを通じて簡単なwebチャットルームを開発します.
次はコードクリップです.
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);
}
}
}
ソースコードをgithubにオープンソースしました
長接続に基づいて開発されたweb版簡易チャットルーム
長い接続は頻繁なポーリングを避ける.しかし、サーバが長い接続を維持することは、追加のリソース消費もある.大同時時の性能は理想的ではない.スモールアプリケーションでの使用も考えられます
クライアントはhtml 5のwebsocketプロトコルを使用することを提案し、サーバ側はswooleを使用する.
swooleについては、ここを突いてもいいです.