Внедряване на ASP.NET чат с помощта на Long Polling

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

И пред мен изникна въпросът - как са го направили? Как са осигурили толкова висока скорост на връщане на свежи данни? В края на краищата уеб сървърът е сървър, който може да отговаря само на потребителски заявки, но със сигурност не инициира самостоятелно заявки.

Кратко търсене в Интернет ми даде отговор. И този отговор е “Дълго запитване ”, а има и друго име за технологията -Комета.

И така, как работи?

Всъщност това е все същият добър стар AJAX и използването на обектаXmlHttpRequest. С една голяма разлика, заключена от страната на сървъра. Разликата е следната. Клиентът изпраща XHR заявка и чака дълго време за отговор на сървъра. И „дългото време“ на отговора се осигурява от самия сървър, който не дава веднага данните на клиента, а само когато има свежи данни в опашката, тоест когато наистина има какво да каже.

Клиентът, след като изчака отговор, го обработва (например показва съобщение на страницата) и след това, без забавяне, отново изисква сървъра. И пак чакане.

Ако, след като е изпратил заявка, клиентът не е изчакал отговор поради изчакване, тогава той иска отново сървъра. Откъде идва този таймаут? Но сървърът просто няма какво да отговори, така че не дава на клиента резултата от заявката. Очакване. Но без да чака, прекъсва връзката чрез изчакване. Такава е простата схема.

Това се наричаДългоАнкета, тоест дълга анкета.

Но от думи към дела. Сега ще направим сървърната и клиентската част на прост интернет чат, изграден върху описаната технология. Ще разгледаме подробно работата на целия сървърен и клиентски код и дори в края на статията ще получим връзка към напълно функционален продукт. Веднага трябва да кажа, че има някои ограничения. Вие, например, няма да можете да го използвате в режим на тежко натоварване, тоест присъствието на голям брой клиенти едновременно. Няма схема за почистване на „загубени“ връзки. Това е само работещ казус. Предлагам ви всички липсващи аспекти на кода за независима редакция.

И така... Без много да мисля, ще дам списък с кодове тук и ще обясня принципа на неговото действие.

Редове 6-14 - капсулирайте класа на съобщението от потребителя, както виждаме, има и метод, който преобразува обекта в JSON низ. Като цяло, по добър начин, тук трябва да използвате нормален JSON сериализатор, а не ръчно да ограждате низа.

Следното е описание на класаCometServer, в който живее цялата сървърна логика на технологиятаLongPolling.

Обърнете внимание, че променливата _clientStateList (ред 24) съхранява всички клиенти, свързани в момента със сървъра.

МетодътPushMessage (ред 24) преминава през целия списък с клиенти и записва съобщението, предадено му като аргумент в изходния поток на всеки, естествено след сериализирането му. След това за всеки клиент се извиква безотказно методът CompleteRequest(), който завършва асинхронната заявка, предавайки резултатите от нея на клиента.

МетодътUpdateClient (ред 51) намира клиента в clientStateList и актуализира всички негови параметри, като например HttpContext, чрез GUID на клиента, който получава. Товагарантираме, че списъкът с клиенти е винаги актуален след всяко повторно свързване.

МетодътRegicterClient (ред 69) /има правописна грешка в името му, коригирайте го сами, ако е необходимо :)/ добавя нов клиент към опашката.

МетодътUnregisterClient (ред 80), съответно, премахва клиента от опашката. Което е напълно законно. Защо да уведомявате клиента за нови съобщения в чата, ако той е напуснал чата отдавна?

Следното е описание на класаCometAsyncState. Защо го създадохме? Да, за съхраняване на клиентски опции катоCurrentContext, AsyncCallback и ClientGuid. Е, това е така, че отделна нишка, създадена в пула от нишки и отговаряща за един клиент, може действително да функционира и да взаимодейства с клиента. Този клас е основно само набор от мъничета за интерфейсните методиIAsyncResult плюс методCompleteRequest (), който извиква функциятаобратно извикване, когато нишката приключи.

И разбира се, кодът на манипулатора на сървъраcomet.ashx, който обработва командите на клиентския скрипт. Веднага ще кажа, че този манипулатор е асинхронен и следователно не е наследен отIHttpHandler, а отIHttpAsyncHandler

Основната логика на програмата се крие в методаRequestWorker (редове 51-95), който в зависимост от командата, получена от клиента, или регистрира / дерегистрира клиента, или изпраща съобщение. Или актуализиране на данни за клиента, когато се свърже отново.

Тук можете да изтеглите готов работещ проект за чат. За да го тествате, просто го стартирайте в две страници на браузъра и опитайте да изпратите съобщение в един прозорец. Дръж под око втория прозорец.