Long-polling простейший пример

Доброго времени читатель.
Если тебя заинтересовал пример реализации реал-тайм приложений, и ты не мог найти нормального примера реализации long-polling то ты попал куда нужно.

Когда-то я тоже не мог найти примитивнейшего примера и таки сделал его сам.

На сколько ты знаешь, принцип long-poll простой и эффективный.
Работает по принципу. Держу соединение с сервером пока не получу каких-то данных, вот та самая избитая схема


Приведу немного примитивного кода, показывающий основные принципы работы. Начнем реализацию примера, ограничемся 4-мя файлами

1. message.php — файл выполняющий роль клиента
2. im.php — файл выполняющий роль проверки новых данных и ответ клиенту
3. check.php — файл отдает изменения
4. im.txt — файл выполняет роль, места где мы считываем данные, новые или старые

Приведем сразу пример содержимого и его описания для первого файла
Содержимое файла message.php

<html class="no-js" lang="en"><head>
    <meta charset="utf-8">
	<title>Long-polling</title>
	<script src="http://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
</head>

<body>
<h2>Содержимое файла:</h2>
<div id="content">
<?php echo file_get_contents("im.txt"); ?>
</div>
<script>
	function check(t){
		$.ajax({
			url: 'im.php',
			method: 'POST',
			data: { "ts": t, "wait": 20 }, 
			success: function(data){
				var d = JSON.parse(data);
				localStorage.setItem("ts", d.ts);
				$('#content').html(d.content);
				setTimeout(check(d.ts), 1000);
			}
		});
	}
	var t = localStorage.ts;
	check(t);
</script>


</body></html>

На этой странице мы сразу считываем содержимое файла im.txt и выводим в блок #content. Далее объявляем js функцию check() которая с заданным интервалом в 1 секунду сама себя вызывает, но принимает каждый раз в себя аргумент timestamp. Запрос мы посылаем на im.php

Содержимое файла im.php

<?php
ini_set('display_errors','On');
error_reporting('E_ALL');

// Последнее изменение файла
function getLastModified(){
	$ts_file = file_get_contents('http://phpmonkey.ru/check.php');
	return $ts_file;
}

if($_SERVER['REQUEST_METHOD'] == "POST"){
	
	$ts = $_POST['ts'];
	$wait = $_POST['wait'];
	
	if($ts === "undefined"){
		$data['ts'] = getLastModified();
		$data['content'] = file_get_contents("im.txt");
		echo json_encode($data);
		return;
	}
	
	// Текущее время плюс ожидание
	$w = (time()+$wait);

	// Крутим бесконечный цикл
	while(true){
		
		// Проверяем изменение файла
		if($ts < getLastModified()){
			// Сразу возвращаем ответ если было изменение
		        $data['ts'] = getLastModified();
			$data['content'] = file_get_contents("im.txt");
			echo json_encode($data);
			return;
		}
		
		// Отдаем ответ после максимального ожидания
		if(time() >= $w){
			$data['ts'] = getLastModified();
			$data['content'] = file_get_contents("im.txt");
			echo json_encode($data);
			return;
		}
		
		// Спим секунду
		sleep(1);
	}
	
}

?>

И здесь все предельно просто, крутим бесконечный цикл, даем условие его прекращения в двух случаях:

1. Это когда данные пришли и нужно их отдать клиенту
2. Это когда время ожидания новых данных истекло и нужно разорвать соединение

Содержимое файла check.php

<?php 

	$file = "im.txt";
	$ts_file = filemtime($file);
	echo $ts_file;

?>

Данный файл просто отдает время последнего изменения.
Почему мы делаем именно таким образом? То есть, почему вы подумали бы, мы не проверяем время последнего изменения внутри цикла в файле im.php?

Ответ: Если бы мы, делали проверку внутри, изменения не были бы в результате той функции getLastModified.
Это всё потому что, когда php запускает данный скрипт и крутит внутри себя вызов функции getLastModified(); её результат не изменяется с первого её вызова, то есть, можно сказать php кеширует её результат и отдает всё снова и снова в цикле, поэтому мы не сможем так отследить изменений.

Данный пример есть на этом сайте.
Страница на которой видно изменения «реал-тайм» здесь
Страница, на которой можно изменить содержимое здесь

 

Loading

Long-polling простейший пример: 4 комментария

  1. автору респект, особенно за то что можно сразу демо пример потыкать! так держать!

  2. Здравствуйте.
    Скажите пожалуйста сильно ли грузит виртуальный хостинг данный чат?

    1. Это сложно назвать чатом.
      Не выяснял на сколько данный пример нагружает процессор.
      Но хостинг не ругается, уведомлений и прочее, никаких не присылает.

  3. Сколько памяти каждое соединение отьедает, 10000 одновременных клиентов не заткнут php-fpm ?

Добавить комментарий для Юрий Отменить ответ

Ваш адрес email не будет опубликован. Обязательные поля помечены *