Как реализовать базовый «длинный опрос»? - PullRequest
761 голосов
/ 02 декабря 2008

Я могу найти много информации о том, как работает длинный опрос (например, это и это ), но нет простых примеров того, как реализовать это в коде.

Все, что я могу найти, это cometd , которая опирается на инфраструктуру Dojo JS и довольно сложную серверную систему.

В основном, как бы я использовал Apache для обслуживания запросов, и как бы я написал простой скрипт (скажем, на PHP), который бы "долго опрашивал" сервер на наличие новых сообщений?

Пример не должен быть масштабируемым, безопасным или законченным, он просто должен работать!

Ответы [ 18 ]

8 голосов
/ 15 сентября 2009

Спасибо за код, dbr . Просто небольшая опечатка в long_poller.htm вокруг строки

1000 /* ..after 1 seconds */

Я думаю, что это должно быть

"1000"); /* ..after 1 seconds */

чтобы он заработал.

Для тех, кто заинтересован, я попробовал эквивалент Django. Начните новый проект Django, скажем lp для длительного опроса:

django-admin.py startproject lp

Позвоните в приложение msgsrv для сервера сообщений:

python manage.py startapp msgsrv

Добавьте следующие строки в settings.py , чтобы иметь шаблонов каталог:

import os.path
PROJECT_DIR = os.path.dirname(__file__)
TEMPLATE_DIRS = (
    os.path.join(PROJECT_DIR, 'templates'),
)

Определите шаблоны URL в urls.py следующим образом:

from django.views.generic.simple import direct_to_template
from lp.msgsrv.views import retmsg

urlpatterns = patterns('',
    (r'^msgsrv\.php$', retmsg),
    (r'^long_poller\.htm$', direct_to_template, {'template': 'long_poller.htm'}),
)

И msgsrv / views.py должно выглядеть так:

from random import randint
from time import sleep
from django.http import HttpResponse, HttpResponseNotFound

def retmsg(request):
    if randint(1,3) == 1:
        return HttpResponseNotFound('<h1>Page not found</h1>')
    else:
        sleep(randint(2,10))
        return HttpResponse('Hi! Have a random number: %s' % str(randint(1,10)))

Наконец, шаблоны / long_poller.htm должны быть такими же, как указано выше, с исправленной опечаткой. Надеюсь, это поможет.

7 голосов
/ 09 апреля 2014

Это один из сценариев, для которых PHP является очень плохим выбором. Как упоминалось ранее, вы можете очень быстро связать всех своих сотрудников Apache, выполнив что-то подобное. PHP построен для запуска, выполнения, остановки. Он не создан для запуска, подождите ... выполните, остановите. Вы очень быстро отключите свой сервер и обнаружите, что у вас невероятные проблемы с масштабированием.

Тем не менее, вы все равно можете делать это с PHP и не убивать ваш сервер с помощью nginx HttpPushStreamModule: http://wiki.nginx.org/HttpPushStreamModule

Вы устанавливаете nginx перед Apache (или чем-то еще), и он позаботится об удержании открытых одновременных соединений. Вы просто отвечаете полезной нагрузкой, отправляя данные на внутренний адрес, который вы можете сделать с помощью фонового задания, или просто отправляете сообщения людям, которые ждали, когда поступают новые запросы. Это не позволяет процессам PHP оставаться открытыми во время длительного опроса.

Это не только PHP и может быть сделано с помощью nginx с любым языком бэкэнда. Загрузка одновременных открытых соединений равна Node.js, поэтому самый большой плюс в том, что он вытаскивает вас из узла NEEDING для чего-то подобного.

Вы видите, что многие другие люди упоминают о других языковых библиотеках для проведения длительного опроса, и на это есть веская причина. Естественно, что PHP не очень хорошо подходит для такого поведения.

4 голосов
/ 16 января 2014

Почему бы не рассмотреть веб-сокеты вместо длинных опросов? Они очень эффективны и просты в настройке. Однако они поддерживаются только в современных браузерах. Вот краткий справочник .

3 голосов
/ 20 апреля 2011

Группа WS-I опубликовала нечто, называемое "Надежный безопасный профиль" , в котором есть Glass Fish и .NET реализация , которые, по-видимому, хорошо взаимодействуют .

Если повезет, есть реализация Javascript .

Существует также реализация Silverlight, которая использует HTTP-дуплекс. Вы можете подключить javascript к объекту Silverlight , чтобы получать обратные вызовы при возникновении push.

Есть также коммерческие платные версии .

2 голосов
/ 01 октября 2013

Вы можете попробовать icomet (https://github.com/ideawu/icomet), кометный сервер C1000K C ++, созданный с libevent. Icomet также предоставляет библиотеку JavaScript, ее просто использовать, как

var comet = new iComet({
    sign_url: 'http://' + app_host + '/sign?obj=' + obj,
    sub_url: 'http://' + icomet_host + '/sub',
    callback: function(msg){
        // on server push
        alert(msg.content);
    }
});

icomet поддерживает широкий спектр браузеров и операционных систем, включая Safari (iOS, Mac), IE (Windows), Firefox, Chrome и т. Д.

2 голосов
/ 09 февраля 2012

Для реализации ASP.NET MVC, посмотрите на SignalR , который доступен на NuGet .. обратите внимание, что NuGet часто устарел из источника Git , который очень часто встречается совершает.

Подробнее о SignalR читайте в блоге Скотта Хансельмана

0 голосов
/ 28 мая 2019

хорошо, я не знаю, что они думают, но я могу предложить вам только чистое, естественное и блестящее мнение.

1) делать ajax за 5 секунд для каждого пользователя, чтобы вызвать текстовый файл, значение которого иногда равно 0, а иногда 1 2) если кто-то отправит ваше клиентское сообщение, создайте файл с именем id + username.txt с помощью php (это файл, который вызывается внутри первого шага) 3) когда сообщение отправляется в базу данных, оно также вставляет значение 1 в текстовый файл 4) если значение текстового файла равно 1, клиентская сторона попадает на серверную часть для получения сообщения. 5) В конце концов, клиент вызывает функцию, которая вставляет 1 в его текстовый файл.

0 голосов
/ 24 апреля 2018

Простейший узелJS

const http = require('http');

const server = http.createServer((req, res) => {
  SomeVeryLongAction(res);
});

server.on('clientError', (err, socket) => {
  socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
});

server.listen(8000);

// the long running task - simplified to setTimeout here
// but can be async, wait from websocket service - whatever really
function SomeVeryLongAction(response) {
  setTimeout(response.end, 10000);
}

Сценарий мудрого производства в Express, например, вы получите response в промежуточном ПО. Делаете ли вы то, что вам нужно сделать, можете охватить все методы с длительным опросом для Map или чего-либо (что видно другим потокам) и вызывать <Response> response.end(), когда вы будете готовы. В длинных опросах нет ничего особенного. Отдых - это то, как вы обычно структурируете свое приложение.

Если вы не знаете, что я имею в виду, подмечая, это должно дать вам представление

const http = require('http');
var responsesArray = [];

const server = http.createServer((req, res) => {
  // not dealing with connection
  // put it on stack (array in this case)
  responsesArray.push(res);
  // end this is where normal api flow ends
});

server.on('clientError', (err, socket) => {
  socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
});

// and eventually when we are ready to resolve
// that if is there just to ensure you actually 
// called endpoint before the timeout kicks in
function SomeVeryLongAction() {
  if ( responsesArray.length ) {
    let localResponse = responsesArray.shift();
    localResponse.end();
  }
}

// simulate some action out of endpoint flow
setTimeout(SomeVeryLongAction, 10000);
server.listen(8000);

Как видите, вы могли бы действительно реагировать на все соединения, во-первых, делать все, что вы хотите. Для каждого запроса id, поэтому вы должны иметь возможность использовать карту и получать доступ к конкретным вызовам вне API.

...