Pull to refresh

Comments 45

Спасибо за ссылку на threadpool. Сейчас то же самое используем, и пока что боролись с ограничением на потоки с помощью разных «подпорок».
Рад, что чем-то смог Вам помочь.
Понимаете, суть технологии Comet заключается в передаче данных клиентам по инициативе сервера, а не самих клиентов. В идеале это постоянное соединение между клиентом и сервером, и именно сервер, когда считает нужным (по возникновению какого-то серверного события, например), выдает клиенту данные. В том же примере из MSDN, который вы привели, отнюдь не сервер решает, когда данные должны быть отправлены клиенту, это решает клиент путем асинхронного вызова метода веб-сервиса. Таким образом, чтобы обеспечить обновление данных на клиенте в режиме близком к режиму реального времени, вам придется постоянно вызывать данный метод (в частности, по таймеру), проверяя, есть ли серверу чем поделиться. Недостатки такого подхода уже описаны в первом абзаце статьи.
UFO just landed and posted this here
В WCF есть поддержка дуплексных биндингов (через http (wsDualHttpBinding), tcp (netTcpBinding и netPeerTcpBinding) и именованные каналы), с помощью которых сервер может делать запросы к клиенту. Другой вопрос, есть в каком-нибудь js-фреймворке реализация требуемой для этого клиентской части.
Спасибо большое, хороший материал. Вот только разобраться с сорсом было бы гораздо проще, нежели читать здесь.
Если у вас остался этот проектик, не могли бы выложить архив?
Добавил в конец статьи ссылку на архив с исходниками и кратенький мануал.
Скажите, это у вас в интранете или ориентировано на широкий круг пользователей?
Ориентировано на широкий (в перспективе даже очень широкий) круг пользователей, однако, как я уже писал, масштабный стресс-тест такого подхода провести пока не было возможности (честно говоря, мы пока не нашли подходящий способ, поэтому я в конце статьи просил поделиться наработками, если кто-то сталкивался с подобным). Лично я проверял на 25 клиентах (и сервер, и клиенты были на одной машине) при пушинге частотой до десятка раз в секунду, при этом нагрузка на CPU была настолько мизерной, что стандартным Task Manager'ом ее даже невозможно было разглядеть.
UFO just landed and posted this here
Спасибо, за статью!
Некоторое время назад я проделал подобную работу (задача, правда, немного отличалась) и столкнулся с проблемой, что, не получается определить подсоединен ли еще клиент или уже закрыл страницу.
Может оказаться, что вы обслуживаете уже давно «мертвых» клиентов.

В моем случае, основное отличие было в том, что обновления приходили очень нерегулярно. В течении одной минуты их могло быть сотня, а потом в течении часа затишье.
Использование события unload для определения дисконнекта клиента является, наверное, самым очевидным решением для решения данной проблемы. Минус, правда, тоже очевиден — реконнект клиента при постбэках. Интересно узнать, как Вы решили эту проблему?
Эта идея хорошо сработает для переходов на другие страницы, либо для правильного закрытия окна,
но совершенно не работает при разрыве связи или других аварийных ситуациях.

Как вариант, можно периодически писать что-то (проблемы, например) в поток OutputStream. По идее, если клиент отключился, то будет ошибка и св-во IsConnected обновится.
Я не проверял этот метод, может вам будет интересно проверить.
Вы не подскажете, пока клиент ждет, можно ли отправлять другие аякс-запросы? Другими словами — сколько одновременных запросов можно слать?
По ссылке инфа только про IE. Нету ничего про другие браузеры.
Вообще по стандарту рекомендуется открывать не более 2 соединений на домен.
В данном случае получится один гонит данные в одну сторону, другой в другую. Чтобы можно было передавать разные данные, нужно использовать мультиплексирование, например, Bayeux Protocol.
Спасибо за статью! Интересная тема и написано хорошо. Возможно я невнимательный читатель, но у меня остался один вопрос. В начале вы описали задачу и все было затеяно (как я понял) с целью применть этот Comet for ASP.NET подход в своем проекте. Так вы его применили в конце концов или нет? Какие у вас были результаты? Проблемы?
Как раз вчера пришла спецификация, сегодня начинаем наращивать на этот Comet-скелет сухожилия и мышцы. Предварительные результаты описаны в этом комментарии. Как дойдет дело до масштабных испытаний и стрессовых нагрузок, отпишу дополнительно.
Ну думали про использование готовых серверов/клиенских библиотек для организации Comet взаимодействия? Есть ведь много чего, в том числие модули для nginx и вспомогательные библиотеки для клиентской стороны. Еще интересно, как расчитывали сколько потребуется ресурсов на сервер для поддержки постоянно открытых соединений.

Запросы раз в 5 секунд кстати вовсе не факт что будут создавать свое соединение, но это мелочи, для realtime действительно лучше comet или websockets (когда заработают).
О готовых решениях думал, читал. Однако Comet настолько заинтересовал, что дико захотелось реализовать самому. Кое-что из этого желания, как видим, все-таки вышло :) Что касается ресурсов, какие именно вы имеете в виду?
Я встерчал например что на 10000 соединений нужно 450Мб памяти, по 45Кб на соединение. По крайней мере с этого началось и двигалось в сторону уменьшения в этой статье: aleccolocco.blogspot.com/2008/10/gazillion-user-comet-server-with.html. В этой статье рассматривался Linux/C++, интересно что покажет .NET.

Мне интересно какой например нужен VPS хостинг чтобы поддерживать Comet соединения.
Сегодня попробуем померять все это дело.
Скажите, а зачем вы делаете вот это:

newGuid = Guid.NewGuid();
if (_clientStateList.Find(s => s.ClientGuid == newGuid) == null)

Разве свежесгенерированный GUID не является уникальным во времени и пространстве? По крайней на одной и той же машине два последовательных значения GUID точно должны быть уникальны. Т.е. вторая строчка похожа на какую-то дикую перестраховку, т.к. заведомо дает true.
Это на всякий случай, вдруг (раз в 100 лет) программа сгенерирует Guid, который уже зарегистрирован в системе…

Как говорится — береженого…
По-моему под вашим сервером быстрее вулкан проснется, чем гуид совпадет :)
Под моим — возможно, но уважаемый ОП считает иначе :)
Вероятность того, что значение нового Guid будет содержать одни нули или окажется равным какому-либо другому Guid, предельно мала. ©MSDN

Предельно мала, но все-таки не равна нулю.
Глядя на ваш код C#, у меня осталось ощущение, что на вас давит тяжкое наследие Си. Так ли это?
Я думаю, что C#-код можно было бы сократить раза в 2, подняв читабельность
Скорее это пережитки не так давно покинутой предыдущей конторы с ее тоннами документации по оформлению кода. Если не сложно, укажите на конкретные места и лучшие решения — учиться, как говорится, никогда не поздно.
и лучшим тому подтверджением будет ссылка на архив с вашим компактным и читаемым вариантом
Договорились. Только вечером, когда домой приду.
Привет, а вот и читаемый вариант:
www.filefront.com/15440909/skeleton.zip

Введения:
— autoproperties
— in-place init
— выкинул locker object — он не нужен, у вас карго-культ имхо.
— прикрутил read-only везде, где можно.

В методических целях и проверка guid «на существование» не нужна.
Ссылка умерла, обновите, пожалуйста
Вот люди тоже пилят свой aspcomet. Релиза пока нет, и фишки с threadpool тоже нету. Но зато обещают Bayeux.
В ASP.NET есть встроенная возможность для AJAX запросов UpdatePanel.По идее, можно совершенно без проблем прикрутить её к Long Polling Requests и сразу убьем двух зайцев.
При этом практически избавляемся от клиентского кода и используем стандартные механизмы ASP.NET.
При этом, конечно, можно незначительно потерять в быстродействии, если объемы большие, но о такой возможности, как минимум, стоит знать.
Упаси вас прогресс вообще пользоваться UpdatePanel.
как по прошествии времени проявило себя Ваше решение?
Спасибо за статью. При реализации появился странный баг. — при добавлении файла global.asax — второй запрос висел (первый не отпускал сервер), дело оказалось в методе Session_start. Начал копать дальше и выяснил, что не даёт освободить запрос — интерфейс System.Web.SessionState.IRequiresSessionState. Вместо его следует использовать: IReadOnlySessionState. Происходит это потому что для записи сессия доступна только одному потоку, а остальные ждут. В режиме же чтения проблема многопоточности разрешается — читать могут все.
Не приведёт ли к утечкам памяти то, что вы сохраняется объект HttpContext в статическое поле (по сути глобальная переменная)?
Класс CometClientProcessor вы имеете в виду?
Могут быть утечки, если не учесть все особенности дисконнекта клиента (а здесь они не все учтены и не все совсем корректно, код старый). Можете на досуге поразмыслить, как эти утечки исключить :)

А вообще данную статью в силу непрерывно текущего времени нужно уже рассматривать как своеобразный экскурс аля «примерно вот так оно работает», т.е. исключительно для расширения кругозора. На практике давно уже можно пользоваться готовыми бесплатными решениями, коих нынче много развелось, например SignalR.
SignalR это, конечно, хорошо. Но открыв его исходники, становится как-то страшно.
Кода столько, как будто собственный веб-сервер написан, и к тому же он привязан к jQuery, что мне вовсе не подходит.

Утечки по идее можно обойти используя HttpContext.Current.Cache (чтобы по таймауту всё само удалялось если долго не используется).
Меня больше интересует, нет ли какой-то встроенной в asp.net альтернативы используемому здесь ThreadPool и без тех проблем описанные у вас, и к тому же чем он лучше, ведь он также создаёт поток?
Sign up to leave a comment.

Articles