Pull to refresh

Comments 55

в данном случае преймуществ по сравненению с long polling почти нет:
1. long polling поддерживается всеми браузерами, в отличии от SSE
2. и в случае SSE и в случае long polling нужен evented сервер
Соглашусь, что поддержка браузерами — слабая сторона. Но SSE более удобный/простой интерфейс работы, в частности с ошибками.
Long Polling требует реконнекта после получения сообщения от сервера, например в том же чате на 10к юзеров это будет не очень хорошо и быстро.
Если у вас есть keep-alive (а он у вас есть), то tcp реконнекта не будет.
Время, как всегда, покажет, что лучше. Мне лично больше импонирует WebSocket.
А я, честно говоря, не понял отличия от WebSockets… Тоже самое они делают.

К тому же, с WebSockets аналогичный чат можно реализовать даже меньшим количеством кода. И код этот гораздо проще будет, сравните.
1. SSE работает в сиплекс режиме.
2. поверх HTTP.
3. Насколько мне известно, драфт вебсокетов сейчас потенциально небезопасен, поэтому в некоторых браузерах он вырублен по дефолту.
уже и драфт исправили и включат сокеты :)
Драфт действительно исправили уже?
Кстати, а Mozilla что-нибудь по этому поводу уже говорила? Когда добавит поддержку WebSockets в релиз?
В Firefox 6 обратно включат вебсокеты, починенные.
Хотя, тот же «потенциально небезопасен» можно повторить в Flash / Java и никто на это не жалуется, а тут производители браузеров завелись.
Пример не работает (@Chat: connection error). Хабраэффект?
Хм, а как получилось уронить ноду если туда стучится всего максимум сотня человек( это вообще мало )
Похоже на то, что фронтенд нодстера глючит. Приложение нормально запускается:
$ nodester app info sse-chat
nodester info Gathering information about: sse-chat
nodester info sse-chat on port 10299 running: true (pid: 18353)


$ nodester app restart sse-chat
nodester info Attemping to restart app: sse-chat
nodester info app restarted.


$ nodester app logs sse-chat
nodester info Showing logs for: sse-chat
Munging require paths..
Globallizing Buffer
Reading file...
Nodester wrapped script starting (18369) at Thu, 02 Jun 2011 09:39:33 GMT
[INFO] Nodester listening on port: 10299
Online: Thu Jun 02 2011 09:39:33 GMT+0000 (UTC)


Пишу багрепорт
Напишите в хабраящик email — возможно, удастся ускорить процесс ;)
> WebSockets
> Это двоичный дуплексный протокол

Двунаправленный же, бо bidirectional.
дуплексный он какбэ подразумевает двунаправленность
Ок, либо двунаправленный, либо (полно)дуплексный, но никак не двоичный дуплексный.
да, конечно. «двоичный» тут вообще не понятно к чему
двоичный в смысле — бинарный, я так понял.
Он был бы двоичным aka бинарным, если бы позволял пересылать только сырые байты.
А так — строки, блобы и типизированные массивы к вашим услугам.
что значит только сырые байты?
мы не можем представить строки в виде этих сырых байт?
> что значит только сырые байты?

byte[] b; // Где-то в Java-программе

> мы не можем представить строки в виде этих сырых байт?

Можем. Но удовольствие работы с такими строками мы оставим ниндзям клана Ассемблера.
PubSub для клиент-сервера? Хм. А почему бы и нет?
А можно вопрос использовал технологию Long Polling, встретился с проблемой, что некоторые броузеры (сейчас уже точно не помню, кажется Chrome) на все время действия запроса показывал индикатор загрузки…

Тестировали ли вы Long Polling в разных броузерах? Как результаты с индикатором загрузки ??
Помогает ли посылка заголовка Content-Type: text/event-stream бороться с этим ??

P.S. Руками и ногами за WebSockets, но увы не могу себе временно позволить этого счастья. :(
почему? работает везде уже давно. где нативно, где через флеш. давно можно забыть, библиотеки делают это прозрачно для разработчика
Через flash — это костыль… FF и Opera до сих пор не держат WebSockets не говоря уже о мобильных браузерах…
100%. Плюс танцы с бубном вокруг веб серверов. А мне необходимо приложение работающее во всех браузерах и деплоящееся на все веб серврера.
socket.io — и точить ничего не надо, но нативный сервер только под Node.js
А в socet.io, как и в Socket.IO-node нет поддержки sse получается?
«Опера» держит, но выключено по-умолчанию. Из-за проблем с безопасностью протокола, которые недавно, вроде, исправили (см. комменты выше).
Необходимо немного подождать, а только потом отправлять запрос. Первичная загрузка пройдет и запрос будет отправлен тихо.
Для того, чтобы у некоторых браузеров не было бесконечной загрузки мы вместо $.ready выполняем setTimeout:
setTimeout(function () { 
// Ставлю именно таймаут, а не $.ready иначе у вебкитов будет бесконечная загрузка

// код

}, 50);
Бесконечная загрузка у хвалёных JSONP.
Обынчый XMLHttpRequest (в т.ч. Long Polling) открывает соединение без полос загрузки.
Увы при одном условии это не так — если в Chrome или Safari в методe jQuery.ready (или просто в скрипте в теле страницы) выполнить длинный запрос: SSE, XHR или загрузить большую картинку через new Image, то пока ресурс не закроет соединение «загрузка...» не пропадет. Как лечить — комент выше.
Радует.
Поднимет стабильность у javascript-фреймворков для подобных соединений (например, now.js), используя альтернативные теххнолгии для современных брузеров.
Думаю в минусы «Long Polling», ещё надо добавить «Много открытых соединений».
Соединений столько же, как и при sse/ws. Реконнектов — да, больше.
Думаю можно добавить «Много висящих процессов/тредов» в некоторых реализациях.
Вот как работает чат через прокси:
@ChatBot: Maxim online
@ChatBot: Hello, Maxim
@Chat: connection error
@ChatBot: Maxim online
@ChatBot: Hello, Maxim
@Chat: connection error
@ChatBot: Maxim online
@ChatBot: Hello, Maxim
@Chat: connection error
@ChatBot: Maxim online
@ChatBot: Hello, Maxim
@Chat: connection error
@ChatBot: Maxim online
@ChatBot: Hello, Maxim
@Chat: connection error
@ChatBot: Maxim online
@ChatBot: Hello, Maxim
@Chat: connection error
Maxim: Hi
@ChatBot: Maxim online
@ChatBot: Hello, Maxim
Welcome to EventSource Chat!
Зашел написал «Hi» и перешел на другую вкладку, а потом смотрю — там уже тьма вот таких hello/online/connect (:
Для sse необходимо держать постоянное соединение. connection error — значит сервер закрыл соединение или «кончился интернет». Постоянный реконнект — это поведение браузера.
А я думаю, что это наш корпоративный прокси так меня унижал (:
Эх, Михаил почему то так и не дописал в статью.

В данный момент уже можно использовать SSE почти во всех браузерах, за исключением IE.
Метод грязный но рабочий, суть метода проста, мы отсылаем обычный XHR запрос, на сервере отдаём заголовок event-stream и не рвём соединение, вот и всё мы получаем постоянное соединение с сервером.

Ниже код JS+php

//JS side of dirt SSE
//timeout to load indicator skip
setTimeout(function(){
var transport = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
transport.open('GET', 'test.php', true);
transport.onreadystatechange=parse;
transport.send();
},500);

function parse(){
//make element with id = response inside html or use console.log
document.getElementById('response').innerHTML = this.responseText;
}


<?php
//php side of SSE
set_time_limit(0);
header("Content-type: text/event-stream");

while(true){
echo time().'
';

//ob_flush and flush is needed, without it not be output
ob_flush();
flush();
sleep(1);
}
?>
Не совсем.

Вся соль именно в заголовке, в том же хроме, если делать без заголовка то отдачи не будет.
Насколько я понимаю это просто впиленный draft SSE на будующее, когда ещё только планировали то заголовок впилили а обёртку нет.
Поэтому так и работает.
В том же хроме давно есть SSE. Но заголовок «Content-type» в XMLHttpRequest ни на что не влияет (даже если там будет Content-type: стихи/пушкина), кроме появления свойства responseXML (Content-type: text/xml). Функция parse же вызывается несколько раз из-за того, что проходят куски данных (php функция flush) и срабатывает переключение на readyState 3 несколько раз.

В пруф я хочу вам показать пример:
Зайдите на страницу javascript.ru/ajax/comet/xmlhttprequest-interactive, в консоли фаербага запустите вот этот код (он идентичен вашему):
var request = new XMLHttpRequest()
request.open('GET', 'http://javascript.ru/server_push/long_digits.php?r=0.8904660024932128', true);
request.onreadystatechange = function(){
    console.log('readyState: %d, responseText: %s',request.readyState, request.responseText);
};
request.send();

На выходе будет что-то такое:
readyState: 1, responseText:
readyState: 2, responseText:
readyState: 3, responseText: 1 2
readyState: 3, responseText: 1 2 3
readyState: 3, responseText: 1 2 3 4
readyState: 3, responseText: 1 2 3 4 5
readyState: 3, responseText: 1 2 3 4 5 6
readyState: 3, responseText: 1 2 3 4 5 6 7
readyState: 3, responseText: 1 2 3 4 5 6 7 8
readyState: 3, responseText: 1 2 3 4 5 6 7 8 9
readyState: 3, responseText: 1 2 3 4 5 6 7 8 9 10
readyState: 4, responseText: 1 2 3 4 5 6 7 8 9 10


Это и называется «XMLHTTPRequest: Interactive». Если же выдачу «причесать», то мы получим ваш эмулятор SSE. Так что я ничего не упустил ;)

Подробнее про readyState и о том как он срабатывает: www.quirksmode.org/blog/archives/2005/09/xmlhttp_notes_r_2.html
В хромиуме линукс ваш код выше выдаёт сразу

readyState: 2, responseText:
readyState: 3, responseText: 1 2 3 4 5 6 7 8 9 10
readyState: 4, responseText: 1 2 3 4 5 6 7 8 9 10

Именно про это я и пытался пояснить, может быть не очень подробно расписал :) извините тогда.

Версия Chromium 11.0.696.68 (84545)

Также и мой код выше если убрать заголовок не будет срабатывать кусками, а просто тупо повиснет.
А с заголовком отдаёт кусками, это скорее всего из за разной реализации readyState или из за глюка какого, именно этот глюк и побудил меня тогда искать вариант SSE потомучто Interactive не работал.
Я не знаком с Node.JS. Такой вопрос: я правильно понимаю, что вызов client.response.write() внутри Clients._send() не вызывает запись в сокет, а складирует переданную строку во внутреннюю очередь на запись? Второй вопрос: именно поэтому нам нужен evented сервер, как писали в комментариях выше, чтобы в произвольный момент можно было добавлять новые куски данных на запись, не блокируясь?
Sign up to leave a comment.

Articles

Change theme settings