MCP
Показаны сообщения с ярлыком программирование. Показать все сообщения
Показаны сообщения с ярлыком программирование. Показать все сообщения

среда, 11 августа 2010 г.

ADD2010: Использование сертификатов в web-приложениях

Недавно приняли мой доклад на конференцию разработчиков ADD, в котором я приведет базовые сведения о шифровании, https о сертификатах, зачем их стоит применять. Затем расскажу о возможностях авторизации при помощи сертификатов в любых браузерах, без паролей и других сложных схем, использовании ЭЦП с помощью javascript и ActiveX для того, чтобы получить проверяемое подтверждение от клиента, также немного расскажет про OID’ы сертификатов, о том, как проверить сертификат на корректное использование для целей приложения.

На мой взгляд тема весьма интересная, и в данный момент становится весьма актуальной, поскольку несмотря на долгое затишье с сертификатами, в настоящий момент они начинают использоваться гораздо активнее. Кроме того, если наше правительство в рамках развития госуслуг начнёт выдавать всем именные сертификаты, мы получим пользователей с сертификатами, которые смогут подписывать документы, да и анонимности будет меньше (хорошо это или плохо, отдельный разговор).

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

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

Показывать и рассказывать буду всё на примере .NET и Windows, про сертификаты X.509.

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

среда, 21 июля 2010 г.

Раскраска Twitter через Opera user CSS

Сегодня я расскажу как ещё можно усовершенствовать сайт твиттера с помощью Opera. В прошлый раз я рассказывал про хитрый скрипт, который разворачивает ссылки и картинки. В этот раз займёмся внешним видом вашей страницы.
Точно также, как и в прошлый раз, создаём css-файл и в настройках сайта прописываем путь к нему.


Дальше начинается самое интересное. Мы будем писать стили для твиттера. У него весьма грамотно сделаны стили, поэтому это просто сплошное удовольствие.

Увеличение ширины страницы

Хоть твиттер и не предполагает широту взглядов, всё-таки на широких мониторах он выглядит немного узковато. Исправим это:
.subpage {width:883px !important; }
.footer {width:883px !important; }
.status-body {width:545px !important;}
#status {width:635px !important;}
#update_notifications {width:485px !important; }
В этом примере я увеличил ширину страницы на 120 пикселей. Т.е. поправил существующие значения на +120. Никто не мешает вам изменить всё это на свой вкус и сделать твиттер резиновым.

Выделение своих твитов

Берём класс .mine и раскрашиваем себя, чтобы было заметно.
.mine {background-color:#ffffe0 !important;color:#407010;}

Выделение чужих твитов

Тут всё тоже просто замечательно. Например, мы хотим выделить отдельно @pdidenko. Берём класс .u-pdidenko и красим его в симпатичный зелёный цвет
.u-pdidenko {background-color:#30ff30 !important;color:#407010;}
Естественно для каждого человека нужно раскрашивать отдельно. Для более сложной логики придётся использовать javascript или ещё более хитрые схемы. Но думаю, что если вы действительно читаете свою ленту, то там не так уж много людей, которых вы захотите выделить.

Выделение ссылок

Хэштеги, это особые ссылки, подкрасим их:
.hashtag {color: #333399 !important;}
Внешние ссылки тоже:
a.web {color: #1060c0 !important;}
Упоминание кого-то в твитах тоже можно подсветить:
a.username {color: #700030 !important;}

Тут у меня фантазия кончилась, но никто не мешает взять приглянувшийся элемент и в любое время изменить его. Это ведь несложно, и результат виден сразу.

Результирующий CSS не даю, т.к. раскраска может сильно не вписываться в вашу цветовую схему и вам нужно будет поправить цвета. Впрочем, собрать из кусочков целиковый CSS не представляет сложности.

Ну и, конечно, полученный результат будете видеть только вы, для остальных будет та же обычная страничка. С другой стороны, кто им мешает сделать тоже самое, но по-своему?

понедельник, 5 июля 2010 г.

Небольшой Opera UserScript для Twitter

Недавно написал маленький userscript для Оперы, который разворачивает короткие ссылки в твиттере (чтобы можно было видеть, куда она ведёт) и как бонус, показывающий картинки с twitpic и прочих прямо в ленте.

Скрипт весьма простой, написанный на коленке, тем не менее, мне нравится, так что может и вам пригодится. Для того, чтобы он работал, нужно сделать несколько вещей:
1. Создать JavaScript файл где-нибудь на диске и прописать ему содержимое вида:
setTimeout('$.getScript("http://redirector.ufims.com/")', 2000);
2. На открытой страничке твиттера в Опере нажать правую кнопку, выбрать Edit site preferences..., вкладку Scripting и прописать путь до вашего файла. Примерно так:
3. Перегрузить страницу с твиттером

После этого, при наведении на короткую ссылку, она развернётся и будет отображено то, на что она ссылается.

При этом скрипт подгружается с отдельного сервера, так что в случае его изменений, вы автоматически их подхватите. А если скрипт вам не нравится, можете написать свой, гораздо лучше, а мой использовать только как идею.

воскресенье, 4 апреля 2010 г.

4.04

Сегодня не только Пасха, но и более IT-шный праздник, а именно День Web-программиста. Также празднуют все причастные разработчики, кодеры и верстальщики, в общем все те, кто сталкиваются с вебом. Ну и пользователи могут присоединиться, выпить бутылочку-другую пивка в честь нелёгкого труда программистов.


Сегодня web-разработчики купаются в фонтанах, раскидывают везде теги, пристают к прохожим с вопросами: "Ты под какой браузер верстаешь?", "Пользуешься ли IE6?" и "Что юзаешь, jQuery или табличную вёрстку, ииик?".


К сожалению при попытках выяснить более детальную информацию, я натыкался на полное непонимание со стороны поисковиков, возможно информация об этом дне скрыта и находится под грифом <div style="display: none;"/>, но зато я нашёл, что сегодня ещё день католического святого Исильдора Севильского, который по мнению цекрви сделал первую версию Википедии  (или по мнению википедии он сделал первую версию энциклопедии, в общем, тёмно всё). Тем не менее, с 1998-ого года, Исильдор считается покровителем Интернета. Так что поставьте его иконку на важным роутером, назовите в честь него свой DNS-сервер, и в общем, узнайте, не любил ли он звук бубнов и шаманских плясок. Мало ли что.  

В общем, ещё раз всех причастных и деепричастных веб-разработчиков:
С профессиональным празднегом!

среда, 24 марта 2010 г.

Перевод времени с точки зрения ИТ-шника

Уже давно идут споры о пользе/вреде летнего времени, хорошо это или плохо, и всё такое. На основных доводах я заострять внимания не буду (хотя и на мой взгляд, смысла особого в наличие перехода нет, а вред уж точно есть). Я хочу немного рассказать о том, какие косяки от этого лезут у программистов, ибо с каждым годом, это всё более актуальнее.

Начнём с простого, время бывает UTC и локальное (если не вдаваться в подробности с атомным временем, и всякими календарями). У UTC есть замечательное свойство: оно течёт постоянно и у всех одно и тоже. Т.е. что у программиста в Америке, что у сурового челябинского админа — цифры одни и те же. Соответственно, по возможности хранить время нужно именно в UTC и использовать при внутренних расчётах именно его, конвертируя его для пользователя при выводе на экран. Но на практике, это оказывается не очень удобным, из-за того, что на всех слоях время необходимо конвертировать, в одну или другую сторону, что может привести к страшной путаницы в самом коде и лишним преобразованиям. При этом для локальных программ, вроде бы это всё не страшно, поэтому UTC можно и не использовать, а в результате получаются разные забавные ситуации:
Как-то работали мы с американским заказчиком, во время очередного билда мы закидывали свежую базу с начальными данными. И всё было хорошо, кроме того что всё падало.  Проблема оказалась в том, что сгенерированные данные были в "будущем", и в результате они не находились по фильтру с getdate(). Естественно через 9 часов всё начинало замечательно работать.


Вот небольшой пример того, что может быть, если работать с локальным временем в разных часовых поясах.

Теперь, собственно о переходе на летнее время. Предположим, что у нас есть система мониторинга, которая смотрит живучесть системы раз в минуту, и если она не откликается поднимает тревогу, рестартит приложение, носится с воплями и кричит о том, что всё пропало.
28 марта в 2 часа ночи мгновенно становится 3 часа ночи и по факту система уже не отвечала целый час (!!!) Как результат получим epic fail приложения.

Другой пример: у нас пишутся логи с данными. В последствии мы хотим по ним построить отчёт. Логи длинные, идут годами. Как результат: пишем в UTC, можем получить сдвиг на час в отчёте UTC + Offset который в течение года разный. Пишем в локальном времени: получаем дырку в летнем времени и двойные данные в зимнем (что ещё хуже, если требовать уникальность). В любом случае, ничего хорошего.

Ну и для полноты картины, третий пример, который связан уже с обратным переходом. Представьте себе небольшое кеширование, данные обновляются раз в минуту, в остальных случаях мы просто возвращаем кешированное значение. Когда мы получим два раза по 2 часа ночи, мы в течение целого часа будем сидеть в кеше: надо обновляться когда текущее время больше чем  2:59 + 1, а сейчас опять 2:00. В общем всё просто замечательно выходит. 

А теперь представьте, что делать с системами управления ЖД и авиа-транспортом, когда резко поезда с самолётами начинают опаздывать, а вылета в 2:30 в эту ночь не будет. Представьте, сколько может стоить подобная ошибка со временем в программе?

Так что моё мнение, сугубо со стороны программиста: переход на летнее время может повлечь непредсказуемое поведение программы с такими же последствиями. И что самое интересное, а вот фиг это оттестируешь заранее, просто и не вспомнишь об этом. 

вторник, 9 февраля 2010 г.

Установка Microsoft Security Essentials на Windows Server

Microsoft выпустила весьма неплохой бесплатный продукт Security Essentials, особо его расписывать не буду, просто скажу, что на сервера он не ставится Для серверов нужно покупать ForeFront Security, весьма мощный и навороченный продукт, который как-то даже неуместно сравнивать с Security Essentials. Т.е. для серверов или полная защита или от чужих производителей.

Но, как говорится, если очень хочется, то можно.  Собственно не я это придумал, я это увидел в блоге у Michal Strehovsky, у него всё замечательно расписано тут и тут, и мне собственно добавить уже особо нечего, но я всё же немножко распишу по-русски, для тех у кого плохо с английским или лень выяснять детали, но хочется просто получить детали на будущее):
  1. Инсталлятор распаковывает себя в отдельную папку вида X:\f1d41766d22514f68a08, надо будет найти эти файлы (поиском или через какой-нить ProcessExplorer) пока инсталлятор радостно сообщает о несовместимой версии, и скопировать для опытов (а то файлы удалятся).
  2. Необходимо поставить WinDbg (тут прямая ссылка на x64 бита, это весит 15Mb)
  3. Завести setup.exe в дебаггере и активно подменять тип Windows на несерверный. Как пишет  Michal Strehovsky, это на x64 можно сделать так:

    bp ntdll!RtlGetNtProductType "as /x ReturnValue rcx; gu; ed ReturnValue 1; g"

    или повесить такой Breakpoint bp ntdll!RtlGetNtProductType+0x1A (на x64 как я понял 0x21) и при каждом попадании в отладчик менять значение регистра eax с 3 на 1 (если там другое значение, значит точка останова установлена неверно).
  4. После того как всё начнёт ставится, breakpoint'ы можно убирать и наслаждаться работой свежеустановленного Security Essentials 

Да, и в принципе таким образом можно попытаться установить другие программы, использующие дурацкие проверки на версию системы (напимер, Nokia PC Suite), правда если установщик в MSI, то проще взять ORCA и там поправить LaunchCondition.

вторник, 26 января 2010 г.

Градусник. Последние изменения

С момента последнего поста про градусник прошло достаточно много времени, но напишу я только о недавних, заметных изменениях. Конечно, если вы не заходили на сайт с того момента, то вы увидите как всё сильно изменилось, но в последние пару месяцев стало ещё лучше .

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

1. Изменение домена на .com
Теперь сайт переехал на новый домен yartemp.com, со старого .co.cc, так что теперь всё гораздо солиднее, ну и удобнее мне для управления.  Будем надеяться, что этот домен Яндекс всё-таки осилит и сможет заиндексировать. Всё-таки у него алгоритмы на порядок хуже, если сравнивать с гуглом и бингом. Гугл, так вообще копается в сайте, как у меня дома

2. Появился более или менее нормальный F.A.Q.
Теперь хотя бы пользователи смогут прочитать о том как всё работает и какие проблемы бывают.

3. Теперь на графике показываются день и ночь
Т.е. восход и закат, если говорить научно. Выглядит это примерно так:

Более тёмным фоном показывается ночь, светлым, соответственно день. Будет интересно понаблюдать весной и летом, как меняется температура с восходом солнца.

4. Картинки с графиками теперь сжимаются более эффективно
В код добавлен алгоритм, который сжимает картинки раза в 2 относительно стандартных средств .NET, это всё делается в фоне и незаметно для пользователей, в результате страница обновляется ещё быстрее, и трафика потребляется ещё меньше.

Также ещё есть небольшие изменения и новые фичи, о них рассказано в F.A.Q., в программе yarTemp исправлены некоторые ошибки, теперь она чуть лучше работает на x64 системах, но о наиболее интересных улучшениях я решил написать тут, чтобы знали, что работа идёт, сайт совершенствуется. За последний месяц количество посетителей увеличилось где-то в 3 раза, и это без активной рекламы с моей стороны, что не может не радовать. Всё-таки приятно, когда люди получают свежую и актуальную информацию. Посмотрим, что будет дальше.

понедельник, 18 января 2010 г.

DefaultHttpHandler + PNG + FireFox

Я писал про использование DefaultHttpHandler для отдачи файлов, принципиально ничего не изменилось, я по-прежнему считаю это неплохим способом, но недавно была обнаружена небольшая проблема с этим способом.

Проблема заключается в том, что в .NET 3.5 SP1 (специально уточняю версию, ибо подобный код имеет тенденцию изменяться) данный метод не знает тип MIME для png-файлов и вместо image/png отдаёт application/octet-stream.

Что самое интересное, в большинстве случаев тут ничего страшного нет. Практически все браузеры определят содержимое по контексту и содержимому файла. Но есть одно досадное исключение , и исключение это зовут FireFox. Если попробовать скачать файл в лоб, то он не посмотрит на то, что это картинка и предложит сохранить его.

Так что не забудьте добавить дополнительный код для png-файлов, выставляющий правильный Content-Type. Хотя у меня такое предположение, что в 4-ом фреймворке всё-таки научится данный метод отдавать правильный тип для png-файлов, а также, возможно и других, чуть менее распространённых.

пятница, 27 ноября 2009 г.

Сдача сертификационных экзаменов Microsoft в Ярославле

Собственно, данный пост пишу как отчёт, и как руководство к действию для коллег и желающих сдать экзамен и получить статус. Возможно, если осилите его, то будет всё проще (хотя казалось бы, куда ещё).  Поэтому, на всякий случай напишу очень подробно. Если меня не хватит, или наоборот, я надоем, то можно почитать про опыт Дена Гладких, расписано всё неплохо и коротко. Итак, понеслась:

Зачем всё это нужно?

Думаю, каждый должен решить это сам. Например, я решил так, что если я могу сдать, то почему-бы и нет? Стоит это не очень дорого, на первый взгляд всё не очень сложно, да и стоит попробовать себя в этом. Собственно собирался сдавать я давно (года этак 4 назад начал собираться ), но сдаться решил только сейчас.

Собственно, из плюшек и бенефитов вы получаете только статус MCP, красивый логотипчик и сертификат, и в общем-то всё. Естественно, понты, это святое, и повесить красивую бумажку на стену, или показать её работодателю, это может быть важной причиной.  Но ещё раз повторюсь, реальных, физических подарков вы не получите. Возможно попадёте где-нибудь под акцию, получите книжку, или можете сдать другие экзамены со скидкой, но это в общем-то не очень существенно. Возможно, магазин MCP eStore окажется для вас неплохим вариантом (кружки, ручки, сумки, майки), но доставка в Россию стоит $100, так что лучше для такого искать другие магазины.

Какая бывает сертификация?

Расскажу только в контексте разработчиков, ибо тут всё коротко и просто. Для админов список гораздо шире. Собственно, открываем соответствующий сайт и всё видим. Если не брать в расчёт устаревшие экзамены то получаем:

  • MCP(Microsoft Certified Professional) это даже не статус, а просто факт того, что ты уже что-то сдал и получил доступ к сайту. Никаких бумажек и логотипов, но для сайтов, связанных с Microsoft этого уже достаточно (itcommunity.ru, MCP-клубы, партнёрская программа)
  • MCTS(Microsoft Certified Technology Specialist) базовый статус, который подтверждает знание какой-либо технологии. Если сдавать экзамены из разных областей, то можно набрать толпу таких статусов и получить кучу сертификатов. Полностью он будет выглядеть примерно так (мой текущий статус):
     
  • MCPD(Microsoft Certified Professional Developer) Собственно главный статус для разработчика. Опять же, можно получить несколько таких статусов, самый крутой: Enterprise Application Developer 3.5, но всё равно обидно, что кончились всякие MCAD и MCSD.

Теперь, собственно о том, какие варианты есть конкретно для .NET разработчика:

  • Базовый экзамен, который практически необходим 70-536 (TS: Microsoft .NET Framework – Application Development Foundation), требуется для получения любого другого статуса. Так что рекомендую начинать сдавать с него, если вы ещё не решили, в какую сторону пойдёте. Начинайте с него и не прогадаете.
  • Для того, чтобы получить MCTS нужно сдать по крайней мере 2 экзамена. Собственно, я двигаюсь в сторону .NET Framework 3.5, ASP.NET Applications, так что начал с 70-562 (TS: Microsoft .NET Framework 3.5, ASP.NET Application Development), хотя он должен быть вторым.
  • Чтобы получить MCPD, нужно сдать специальный "Pro" экзамен по выбранной специализации. Т.е. в моём случае: 70-564 (PRO: Designing and Developing ASP.NET Applications Using Microsoft .NET Framework 3.5)
  • Когда выйдет .NET Framework 4.0, дожен появиться специальные Upgrade экзамен, так что, как вы его сдадите, вы получите уже MCPD по 4.0, и не надо будет сдавать всё заново. Но за один экзамен всё-таки заплатить придётся. Так что можете ждать фреймворка 4.0 и не сдавать экзамены 

Собственно, это про экзамены. Ещё раз сайт, на котором можно всё поглядеть и почитать: www.microsoft.com/learning/

Как зарегистрироваться?

Тут, в общем, есть два пути: Prometric и личная явка в сертификационный центр. Первый вариант позволяет проделать все операции сидя за компьютером (к тому же он дешевле), второй позволяет оплатить рублями, назначить экзамен в тот этот же день, да и вообще, идёт общение с живым человеком.  В Ярославле есть 3 сертификационных центра (на пятой странице прометрика, чтобы потом не искать долго):

  • Интернет Центр ЯрГУ (я там сдавал экзамен). В первом корпусе. Тел. 79-77-31
  • КАМИ (вроде первый в Ярославле). Чайковского, 40A (рядом с Мелоди-клабом). Тел. 72-75-55
  • Академия МУБиНТ. Советская 80. Тел. 8-915-969-90-99. Это рядом с Шинным.

Так, что смотрите, где вам удобнее, и можете туда звонить, или идти на Прометрик. Уточню: сдаёте экзамен вы не Microsoft, а отдельной конторе, точнее организации, с кем прометрик заключил договор. Соответственно на них накладываются определённые требования, так что в разных организациях всё должно быть примерно одинаково и принципиальной не должно быть. Кстати, можно сдавать не только экзамены Microsoft, но и другие, но тут я ничего не могу подсказать.

Собственно, как регистрироваться через прометрик:

  1. Идём сюда, и набираем ваучеров для скидок (15-25%, действуют до конца года). Чтобы потом не возвращаться, можно взять сразу три ваучера (они придут на почту), и потом их использовать.
  2. Идём вбивать данные на сайт прометрика: register.prometric.com
  3. Там всё по шагам, так что сложностей не должно возникнуть. В конце нас попросят зарегистрировать и оплатить стоимость экзамена. Так что, если есть карточка, то платим (через paypal нельзя, только в лоб, так что решайте, доверять или нет). Без скидок экзамен стоит $50.
  4. Ждём указанного времени, и минут за 15 приходим сдаваться.
  5. Если не получается в указанное время, можно изменить расписание, или вообще отказаться (вроде за сутки до сдачи, но это лучше уточнить).

Уточнение: Я сдавал в интернет центре ЯрГУ, и меня попросили всё-таки им позвонить, причём до регистрации. Т.е. конечно, они меня примут в любое время дня и ночи, но лучше всё же договориться заранее. Кроме того, они сказали про какой-то сдвиг, так что возможно они скажут что лучше немного другое время указать.

Процесс сдачи

Итак, вы всё-таки заявились на экзамен. Тут всё просто. Нужны права и паспорт (тем, у кого нет прав, наверное нужно позвонить уточнить, что можно принести в замен, и нужно ли в принципе). Когда вы придёте, все документы уже будут готовы и вам всего-лишь нужно подписать бумаги о том, что вы завещаете всё свое имущество будете хорошо себя вести и не списывать. Потом вы дожны отдать все свои вещи и выключить телефон (и лучше его тоже отдать ), получите маркеры и пластиковый листок в качестве черновика (как я понимаю, это всё многоразовое и основная цель, чтобы листок с записями вы не утащили с собой или чтобы сотрудники не выкинули его в мусор), место за компьютером и сам тест.

Собственно все вопросы выдаются прометриком и идут через специальную программу. Пользоваться можно только маркером и калькулятором встроенным в тест (если нужно что-нибудь посчитать). Сотрудников можно вызывать только в случае проблем с компьютером.

Вначале возможно будет небольшой опросник, текст соглашения, возможно, небольшой опросник о ваших предполагаемых знаниях, а потом сам тест. На него даётся 3 часа (на 50 вопросов), что весьма дофига. Я управился со всем за 2, и при этом много тупил. Т.е. при желании можно уложиться и в час (только надо ли?). К любым вопросам можно всегда возвращаться, можно помечать их для последующего просмотра, можно менять решение. Тут никаких ограничений нет. Это весьма удобно, сложные вопросы можно уже пересмотреть в конце экзамена, когда на всё уже ответил и время не давит.

Сами вопросы обычно предлагают выбрать один правильный из четырёх вариантов. Изредка бывает выбор двух-трех вариантов (всегда пишут нужное количество). Вопросы грамотные и сводятся к вариантам вида где мы пропустили запятую? С другой стороны, иногда раздражает, что бывают вопросы, на которые ты просто не помнишь правильный ответ, но знаешь, что из MSDN ты найдёшь его за минуту (с непрограммерскими экзаменами, ещё хуже, бывают задания, которые в жизни делаешь на автомате, и по пунктам уже объяснить не можешь, ибо спинным мозгом нажимаешь на кнопки, а приходится выбирать правильный вариант).

После сдачи, можно будет написать комментарий об умственных способностях составителя, о качестве каждого вопроса, о самой процедуре проведения экзамена (уходит прямо в прометрик, судя по всему, проверяют организацию, которая устраивает экзамен). От них можно отказаться, можно ответить. На это даётся дополнительное время, всё добровольно. При этом вам сразу же говорится, сдали вы экзамен или нет, и автоматом печатается листок с конкретными цифрами, и шкалами вида Тема: слабо/сильно. Т.е. конкретные ошибки неизвестны. Но примерно оценить проблемные темы можно.

На этот листок вам ставят хитрую печать, после этого вы должны его посмотреть, запомнить и съесть. Ибо данные цифры и шкалы больше нигде и никогда не покажутся, это ваше личное дело, что вы знаете. И даже если набрали 701 балл при допустимых 700, этого вы никому не обязаны говорить. Говорите, что 1000, всё равно не проверят.


Далее, если вы в первый раз сдаёте, то вам через некоторое время придёт MCP ID, для регистрации на mcp.microsoft.com, там вы можете сотворить свои логотипы, получить PDF с сертификатом или заказать его ($10 за один + $1 за каждый последующий в одной посылке), на сертификате будет стоять личная подпись самого Стивена Балмера.  Официальный способ при этом подтвердить статус, это Transcript. Для доступа к нему нужен код доступа, который вы придумываете сами и всегда можете изменить, чтобы прекратить к нему доступ. Так что сертификаты, это в общем-то баловство, но красивое.

Подготовка

Ну и в конце, о том как готовиться. Тут я не помощник. Я почти не готовился, решил что свои-то 700 баллов наберу, и очень пожалел. При сдаче экзамена, сомневался практически в каждом вопросе, было ощущение, что я вообще первый раз вижу этот .NET, и вообще, кто здесь?  

Темы для подготовки есть в описании экзамена, а уж как вы будете готовиться: читать книжки, курить брейндампы, копать MSDN или смотреть доклады, решайте сами. Глубоких знаний не требуется, но требуются достаточно широкие (e.g. 70-562): Microsoft AJAX, Mobile Controls, Declarative Data Sources, Control Lifecycle, Deployment, Configuring, Security. 

Вообще, могу сказать, что на MesureUp вопросы близко к теме, а на BrainBench — вообще не в тему.

воскресенье, 22 ноября 2009 г.

Сжатие ViewState

ViewState — в ASP.NET весьма интересная и полезная технология, но у неё есть один существенный недостаток. ViewState может очень сильно увеличивать размер страницы, и кроме всего прочего все эти данные пойдут на сервер назад, что для пользователей с узким каналом может выливаться в "тормоза" приложения, хотя само-то оно будет быстрым.

И что самое неприятное, все эти проблемы активно вылезают обычно ближе к окончанию проекта, когда всё уже сделано, и менять уже логику поздно. Точнее, смена логики может привести к непредсказуемым глюкам, а если всё тестировать заново, то это займёт слишком много ресурсов, так что обычно всё так и оставляют, и на будущее все программисты твёрдо себе говорят: в следующем проекте будем следить за ViewState. Но вы поняли. 

Собственно, есть ситуация, проект близится к концу, нужно что-то с ViewState'ом делать. Для начала, стоит взять типичную страницу, забрать из неё ViewState (он хранится в hidden-поле __VIEWSTATE), убрать кодирование в base-64 (сам ViewState не должен быть зашифрован, естественно), и посмотреть на него. На данном этапе иногда можно выкинуть некоторые элементы, которые случайно попали туда. Например, в одном проекте часть рендера страницы выводилась через asp:Literal, который по умолчанию пихает всё свое содержимое во ViewState, что, например, для русского текста длинной в 100 байт превратится в 300 байт на клиенте.

Но, когда базовые вещи исключены, всё равно может остаться большой вьюстейт (например, у нас в одном проекте с хитрым гридом он был 80 килобайт), и с ним надо что-то кардинально сделать. В этом случае, можно попробовать самое простое решение: сжать вьюстейт, благо ASP.NET предоставляет достаточно простую возможность для этого.

Вначале, нам необходимо переопределить PageStatePersister, собственно, тот класс, который и отвечает за хранение. В ASP.NET существуют две реализации, которые хранят ViewState в hidden-поле (по умолчанию) или в сессии. Нам нужен свой, который будет сжимать содержимое:


protected override PageStatePersister PageStatePersister
{
    get
    {
        return _persister ?? (_persister = new CompressionPageStatePersister(this));
    }
}

Для этого перекрываем property PageStatePersister у страницы (Page), и возвращаем инстанс нашего класса:


public class CompressionPageStatePersister : PageStatePersister
{
    public CompressionPageStatePersister(Page page) : base(page) { }
    public override void Load()
    {
        string requestViewStateString = base.Page.Request.Form["__CVIEWSTATE"];
        if (!string.IsNullOrEmpty(requestViewStateString))
        {
            Pair pair = (Pair)
                ViewStateCompressor.ViewStateDecompress(
                    Convert.FromBase64String(
                        requestViewStateString));
            base.ViewState = pair.First;
            base.ControlState = pair.Second;
        }
    }

    public override void Save()
    {
        Control control = base.Page.FindControl("__CVIEWSTATE");
        if ((base.ViewState != null) || (base.ControlState != null))
        {
            string s = Convert.ToBase64String(
                ViewStateCompressor.ViewStateCompress(
                    new Pair(base.ViewState, base.ControlState)));
            ScriptManager.RegisterHiddenField(base.Page, "__CVIEWSTATE", s);
        }
    }
}

Как видно, реализация простейшая, перекрываются методы Save и Load, которые сохраняют и загружают ControlState (неотключаемая часть, необходимая для работы контролов) и ViewState. Всё это сохраняается в собственное hidden-поле __CVIEWSTATE, т.к. к обычному у нас нет доступа (но если интересно, то с использованием Reflection, нужно взять private field у класса Page с именем _clientState, и записать значение туда).

Да, и в base-64 кодировать обязательно, ибо особенности стандарта HTTP таковы, что даже если вы попробуете другую кодировку, в реальности будет передано гораздо больше байт.

Ну, и собственно про сжатие, точнее про ViewStateCompressor, это небольшой класс, который сериализует данные и сжимает с помощью GZip:


public static byte[] ViewStateCompress(object viewStateToCompress)
{
    ObjectStateFormatter formatter = new ObjectStateFormatter();
    MemoryStream output0 = new MemoryStream();
    DeflaterOutputStream ds = new DeflaterOutputStream(output0, new Deflater(6, true));
    formatter.Serialize(ds, viewStateToCompress);
    ds.Close();
    return output0.ToArray();
}

public static object ViewStateDecompress(byte[] data)
{
    ObjectStateFormatter formatter = new ObjectStateFormatter();
    InflaterInputStream ds = new InflaterInputStream(new MemoryStream(data), new Inflater(true));
    object value = formatter.Deserialize(ds);
    ds.Close();
    return value;
}

Небольшие пояснения:

  • Для сжатия используется библиотека #zipLib (родная медленнее и хуже жмёт, использовать не стоит)
  • Степень сжатия (6) — это по умолчанию, наилучший компромисс качества и скорости
  • Не пишутся заголовки GZip, так как они нам не нужны, т.е. другими словами использоуется не GZip, а Deflate — алгоритм сжатия без дополнительной информации
  • В качестве сериализатора используется ObjectStateFormatter, который и используется в качестве стандартного (точнее там используется LosFormatter, но итогом работы служит строка в base-64, а мы сами потом трансформируем уже запакованные данные
  • В данном случае мы теряем встроенную возможность шифрования ViewState, но её при необходимости легко реализовать, да и расшифровать ViewState будет уже сложнее

Как видно, всё просто: два класса для удобства и один override, и результат — размер данных на клиенте в 2-5 раз меньше, и не на магистральных каналах страницы начинают работать гораздо быстрее.

Да, и постарайтесь не сохранять во ViewState собственные объекты, ибо ObjectStateFormatter достаточно эффективно сериализует базовые типы, но если он не понял про тип, то начинает использовать недостаточно эффективный, но универсальный BinaryFormatter. Если будет время, я постараюсь расписать, как в некоторых случаях можно подменить сериализацию для своих типов, чтобы уменьшить размер ViewState (который из-за этого может тоже весьма значительно сократиться).

среда, 28 октября 2009 г.

Использование DefaultHttpHandler для отдачи файлов пользователю

Тут на конкурсе задали вопрос: чем отличаются Http Handlers и Http Modules. Ответов полно, дублировать их желания нет.  Всегда можно открыть MSDN и почитать про это.

Вкратце, Handler, это обработчик запроса, например, когда обращаемся на /default.aspx, в web.config ищется подходящий обработчик и ему запрос отдаётся на растерзание. Естественно, если вы поглядите в web.config для вашего приложения, вы там скорее всего такого не найдёте. Но если вспомнить иеархию конфигруационных файлов в .NET, то становится ясно, что нужно искать в базовом web.config файле. У меня он находится тут: C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\web.config.

Этот зверь в 30Кб, полностью описывает стандартные настройки приложения, которые можно заменить в своём. Там как раз и есть обработчик aspx-файлов:

<add path="*.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="true">

Собственно он и говорит рабочему процессу, что все подобные запросы должна обрабатывать фабрика с названием PageHandler (фабрика, это небольшой класс, который позволяет уже самостоятельно выбрать нужный Handler, в зависимости от более тонких условий). Также там можно найти другие интересные строчки:

<add path="*.config" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
...
<add path="*.soap" verb="*" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="false"/>

Например, эти говорят что *.config файлы нельзя показывать (например тот же web.config), а *.soap нужно для Remoting. Естественно, все эти правила можно заменить в своём приложении, да и при этом не забыть, что сам IIS по умолчанию не все расширения отдаёт ASP.NET, и надо добавить соответствующий фильтр в  настройках вашего приложения (ну или глобальный, на все файлы).

Про Http Handler's почему-то не получилось коротко, но это я случайно.   Дальше я расскажу более интересную вещь. А пока немножко про Http Modules.

Собственно, с ними всё просто, поскольку файл мы уже открыли и видим что за httpHandlers идут httpModules. Они-то  и будут будут вызваны HttpApplication во время обработки запроса, при этом они могут сделать что-нибудь полезное не прерывая и не перенаправляя запрос. Например, разобраться с сессией, авторизацией или логгированием. Да мало ли чем, всегда их можно подключить и отключить. Например мы хотим фатальные ошибки приложения сразу отправлять админу по ICQ. Сделали модуль, подключили к нужным приложениям. Всё работает, красота.  


Собственно с Handlers и Modules разобрались, переходим к задаче, которую можно элегантно решить с помощью стандартных хендлеров. Задача эта, достаточно частая и состоит в том, чтобы дать возможность пользователям скачивать файлы из нашего приложения, но при этом, как всегда файлы лежат непонятно где и непонятно с каким именем, да и права нужно бы проверить.

Я часто встречал реализацию в виде /getfile.ashx?id=123 — где собственный хендлер как-то пытается отдать файлы. Идея хорошая, но не очень красивая, к тому же приходится рисовать собственный хендлер, отдающий файлы, что как-то неправильно.

Небольшое отсупление, по возможности старайтесь передавать имя файла в запросе, а не через Content-Disposition, иначе будут  проблемы с русскими именами файлов, да и периодические глюки, когда у клиента имя какое-то не такое. Для этого всего-лишь нужно делать запросы вида /getfile.ashx?id=123/requiredFileName немного подправить разбор входящих параметров, а дальше браузер сам придумает как обозвать файл.

Собственно моя идея состоит в том, что нужно использовать существующий DefaultHttpHandler, который и предназначен для отдачи статики, только для этого придётся выполнить пару простых условий:

  • Необходим .NET Framework 3.5 SP1, потому что в предыдущих реализация данного хендлера более примитивная.
  • Файлы должны быть физически доступны из приложения, т.е. пользователь должен иметь теоретическую возможность их скачать (правда имя может быть любое и лежать они могут как хотят. Для запрета прямой скачки, делаем соответствующие правила в web.config)

Теперь, собственно, осталось придумать по какому пути пользователи будут обращаться к файлам и навесить на этот путь свой простенький хендлер, отнаследованный от DefaultHttpHandler. Можете использовать различные url-rewriting решения, или написать своё. Если вам приходится вешаться на aspx файлы, то можете в фабрике возвращать следующий Handler:

PageParser.GetCompiledPageInstance(url, null, context)

Т.е. практически вручную запустить обработку страницы (с некоторым оговорками, но не о них сейчас речь).

Далее, в своём хендлере делаем следующее:

  • В методе BeginRequest  определяем "настоящий" путь к файлу по запросу. Например, запрос, /123/myfile.jpg меняем на /files/storedFile_123.dat
  • вызываем у контекста (вам его передадут) метод: context.RewritePath с полученным путём.
  • Дальше, чтобы не отдавать запрос IIS (а для оптимизации DefaultHttphandler попробует это сделать), что-нибудь пишем в Response, например context.Response.Write(' '). 
  • Вызываем базовый метод BeginRequest

В общем-то всё. Мы подменили путь и сказали обработать его как следует. С докачкой, и прочими плюшками. Но небольшое уточнение, зачем же не стоит отдавать запрос IISу? На самом деле, в определённых случаях это нужно делать, ибо производительность будет выше, но IIS делает пару нехороший действий:

  • Записывает в заголовки Content-Location с настоящим именем файла, т.е. хоть и не страшно, но мы светим то, как у нас хранятся файлы, т.е. неаккуратненько как-то
  • Если он не знает расширения файла, то в целях безопасности может его и не отдать (Свойства сервера, типы MIME — тут указаны расширения, которые IIS знает)

Ещё можно обрабатывать ошибки, писать логи и статистику, но это уже тонкости и детали, главное, что достаточно быстро (гораздо быстрее чем читать этот пост ).


Вышесказанное относится к IIS 6.0, в седьмом, возможно всё будет ещё проще, но я с ним мало работал, и в основном в классическом режиме, так что не буду ничего утверждать заранее.

вторник, 27 октября 2009 г.

Калькулятор размеров мониторов

Я как-то давно написал простенькую страничку, которая по введённой диагонали монитора и разрешению выдаёт его физический размер, dpi и соотношение сторон. Вещь на самом деле очень полезная и интересная, можно узнать, например, что:

  1. Монитор в 22" с разрешением 1920х1080 имеет по вертикали практически такой же размер как и обычная 17"-ка (1280х1024)
  2. Sony Vaio P имеет безумное разрешение в 1600x768, что даёт 222 dpi, что в 2.3 раза меньше стандартной точки (!!) Другими словами, в комплект должна идти лупа
  3. Ноутбуки в 15.4" обычно имеют разрешение 1280х800 что близко к классическим 96dpi (98 если точно)
  4. и многое другое

Надеюсь что данный скрипт поможет вам выбрать подходящий размер монитора, да и просто оценить размеры.

Пользуйтесь.

GAC

Не выдержал и решил написать ответ на вопрос про GAC для конкурса Гайдара про платформу.

Переписывать MSDN и Рихтера не буду, для разнообразия скажу своё мнение про GAC, чтобы ответ отличался от остальных.   Собственно расскажу, не про то, чем хорош GAC, а чем он плох.

Для начала в двух словах про него — это глобальный кеш сборок, и любое приложение, которое использует опредёленную сборку сначала посмотрит на её наличие в GACе, а только потом будет искать в других местах. Т.е. можно считать GAC банальным хранилищем DLLек, как Windows\System32, но с одним важным отличием. Сборки хранятся не по имении библиотеки, а по имени, Strong Name ключу, версии, культуре и платформе (x86, x64). Т.е. можно хранить разные версии сборок и даже умудряться их использовать в одном приложении (хотя лучше постараться не делать так). Т.е. GAC полезная функциональность, но есть несколько НО.

Самое главное, теряется возможность xcopy deployment, необходимо использовать gacutil или делать приличный Installer. Но если подумать, то что нужно класть в GAC? Нужно туда размещать библиотеку, которую будут использовать несколько приложений на компьютере, иначе особого смысла в этом нет. Другими словами, это должен быть конкретный shared-компонент. А кому нужен shared-компонент? Только разработчикам. Для обычных пользователей это в большинстве случаев не нужно. А разработчики очень не любят сложные процессы установки библиотек. Им бы в проект скопировать что надо, и не думать потом о библиотеках. В противном случае получается, что у разработчика может всё работать, ибо сторонняя сборка в GACe, а у клиента уже всё будет падать, ибо разработчик забыл её приложить к приложению.

Например, мой epic fail был с библиотекой Microsoft.mshtml.dll, которая оказалось что ставится со студией, и напрямую в приложении не используется, а используется через третьи библиотеки. В результате, у меня приложение работало на всех компьютерах, а половина клиентов ругалась. Конечно, я уже умный, и подобных вещей стараюсь не допускать, но вот пример как легко можно сломать приложение использованием GACа.

Собственно, если мы планируем использовать сборку в GACе, то у нас сразу усложняется разработка. Необходимо писать скрипты для билда, которые будут выковыривать сборку из GAC, компилировать новую версию и вставлять обратно. Вроде не сложно, но программисты ленивые, и обязательно что-нибудь схалтурят, и при деплое получим проблемы.  Ещё нужно обязательно использовать Strong Name, что на этапе разработки иногда плохо, ибо придётся раздавать ключ всем разработчикам (проблема в секурности), также сразу включается версионирование, которое менять нужно вручную. Иначе получатся две абсолютно разных сборки с версией 1.0.0.0, одна из которых в GAC, а вторая нужна приложению, и это вызовет замечательные проблемы, которые будет очень весело отлаживать.


Собственно, что я хотел сказать:

  • Использовать GAC нужно, когда есть проблемы с версионированием. Это позволит их решить. Например, приложение А использует библиотеки B и С. B использует библиотеку D версии 1.0.0.0, а C использует D версии 1.2.0.0. Как это это необходимо решать. Тут нужен GAC, ибо два файла с одним именем к приложению подцеплять плохо.
  • Использовать GAC нужно, когда есть много приложений, использующих одну сборку. Как вариант — хостинг многих приложений с общим компонентом. И то, может быть проще не использовать GAC, ибо места на диске не так уж и много сэкономится, а если случайно выкинут сборку из GAC, то можно получить проблемы.
  • Хороший пример того, что нужно класть в GAC — системные библиотеки .NET Framework
  • Во всех остальных случаях — не стоит. (Моё личное мнение).

.NET Remoting по протоколу SOAP. Возможно ли?

Тут @gaidar устроил конкурс и задаёт всякие разные вопросы.  В принципе, отвечать на них не планировал, ибо умные ответы писать долго и получится переписывание книжек/MSDN, а глупые можно и в Твиттере

Но, тут задали вопрос про Remoting, а это же моя любимая тема.

Собственно, Remoting может использовать любой канал, хоть голубиную почту, с сообщениями, закодированными морзянкой, этим он и отличается в лучшую сторону, но вопрос именно в том, что можно ли из подобного SOAP/Remoting сделать настоящий Web Service? Ответ сложный, с одной стороны — да, ибо можно использовать SOAP, с другой стороны, эти сообещия будут весьма страшными и заточенными под remoting-клиента, а не обычного Web-Service клиента. Собственно, проблема в том, что для веб-сервисов нужны  WSDL и XSD описания методов, а Remoting хоть и делает WSDL, но делает его для себя, и особо не смотрит на стандартные неймспейсы и типы.

Так что ответ: В принципе да. Но если вы хотите, чтобы клиентами были не только те же .NET приложения, то вам же придётся приложить множество усилий, чтобы использовать только базовые типы, не использовать CAO и эвенты, т.е. сильно урезать функционал Remoting, чтобы свести его к веб-сервисам. А оно вам надо? Гораздо проще тупо и использовать веб-сервисы для тех целей, когда они нужны, это проще и понятнее, а Remoting не использовать вовсе, не нравится он мне. 

четверг, 3 сентября 2009 г.

Немножко про Reflection

Недавно проверял скорость работы Reflection в плане того, насколько оно медленное. Расписывать все случаи не буду, также не буду утверждать что все замеры корректные, просто немного данных для информации, чтобы вы знали, что ожидать от Reflection:

  • Вызов метода через рефлекшен отличается в зависимости от того, является ли метод public или private
  • Для public вызов метода где-то в 100-150 (!) раз медленнее, чем обычный вызов
  • Для private вызов медленнее где-то раз в 400-500 (!). Выводы делайте сами.
  • Время на вызовы GetMethodInfo относительно невелико, при этом, похоже это всё кешируется. Так что особо оптимизировать вызовы тут смысла нет
  • Если вы точно знаете сигнатуру метода, который берёте через рефлекшен (в качестве варианта, пнуть какой-нибудь приватный метод, или при использовании какого-либо варианта плагинов), то можно воспользоваться Delegate.CreateDelegate с указанием нужного типа, получить правильный делегат и его вызов будет таким же быстрым (возможно даже чуть быстрее, есть подозрение на использование call вместо callvirt), как и прямой вызов
  • Если точно не знаете сигнатуру, то можно использовать Delegate.DynamicInvoke но производительность будет примерно такая же, как и у чистого рефлекшена
  • Если хотите использовать Expression для генерации, в частности LambdaExpression то совет тот же. Используйте чётко типизированный .Compile() и получите почти идеальную производительность (где-то 1.5, но компиляция не очень шустрая). С учётом того, что экспрешены — достаточно могучий механизм, подобное стоит использовать. Есть интересные задачи, где они могут сильно облегчить жизнь, или даже сделать что-то особенное.

Ну вот, в общем и всё. Пока для меня остаётся открытым вопрос: "Как использовать преимущества делегатов без возможности указания нужного типа напрямую", чтобы получить хорошую производительность для рефлешкена. Смотрю в сторону DynamicMethod, но это уж больно серьёзная артиллерия (хотя производительность замечательная). 

среда, 5 августа 2009 г.

Как заполнить поле в базе рандомными значениями

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

Для тестов иногда бывает необходимо заполнить поле в базе какими-нибудь левыми значениями. Проблема в том, что обычная функция RAND() при апдейте возвращает одно и тоже значение, ибо оптимизатор её оптимизирует. Собственно, из этого есть выход, заключается он в том, что в RAND() надо передавать рандомный seed в качестве параметра. Вариантов несколько, я использую такой:

UPDATE Table SET Field=RAND(abs(convert(varbinary, newid()) % 65536))*1000 

1000 — это максимальное значение в поле (точнее 999). Т.к. точность не требуется, особо над распределением не заморачивался. Пользуйтесь, если вдруг пригодится.

пятница, 6 марта 2009 г.

Proxy

Жизнь течёт, изменяется, но по-прежнему сохраняется потребность в проксе, хотя казалось бы, интернет шустреет, и зачем оно таки надо?  

Достаточно давно, когда интернет у меня был практически только по диалапу (на работе, правда более или менее приличный, но не шустрый), я написал какую-то безумную проксю с совершенно извращённым кешированием. А именно, она кешировала все картинки намертво, CSS и JavaScript, вроде бы тоже. Страничики тоже кешировались, но слава богу обновлялись, иногда.  Как результат, было удобно смотреть сайты в браузере без интернета (ибо раз нельзя достучаться, результат выдавался из кеша), да и трафик был слегка меньше.

Естественно, всё слегка глючило, кеш портился, да много чего было. Но тогда я разобрался в принципах работы HTTP через прокси, написал свою файловую систему для кеша, проработал механизмы блокировки URL'ов с баннерами. Часть из всего этого пригодилась в дальнейших проектах. Да и урощённый движок прокси тоже активно использовался в одном из них.

На этом можно было бы и закончить, но совершенно недавно я понял, что таки старые наработки ещё пригодятся. Дело в том, что интернет дома развился до неузнаваемости, у меня появился отдельный компьютер, который является сервером и круглосуточно сидит в сети и делает своё маленькое грязное дело.  На работе же, с интернетом всё не так радужно. В результате, после подкинутой идеи, я за пару часиков практически с нуля (используя старые наработки в качестве напоминалок, как надо и как не надо делать) написал сжимающий прокси. Т.е. идея совершенно банальная: на работе есть прокси "клиент", который связывается с прокси "сервером" отдавая ему запросы и получая ответы (которые уже "сервер" скачивает из интернета). И вот эта передача уже идёт запакованная.

Потом, конечно, пошли доработки, в которых я выяснил, что встроенное в .NET сжатие GZip — это унылое говно, которое использовать нужно только по необходимости. В других же случаях гораздо лучше использовать #ziplib, мало того, что жмёт на порядок лучше, так ещё и работает быстрее! Кто там говорил, что в Майкрософте воруют код? Да ничего подобного! Если бы они это делали, они бы не написали такой отстой. Сжатие BZip2 было реализовано, но исключено по причине того, что оно раз в 10 медленнее GZip (точнее Deflate, но это уже тонкости структуры результирующего потока), а результаты в большинстве случаев не лучше. LZMA (7z) — результаты давал ненамного лучше, то скорость у него вообще отвратительная. Были ещё варианты сжатия по заранее заданному словарю, но пока на них забил из-за сложностей в реализации (хотя прирост сжатия должен быть весьма и весьма хорош). Добавил простенькое кеширование, чтобы не перегружать заново некоторые страницы (они реально перегружаются, но если результат такой же, то он не отправляется). Также сделал повторное использование TCP-соединений, чтобы уменьшить их количество и соответственно трафик.

Результаты оказались в принципе достаточно неплохие. Сжатие в зависимости от условий использования вполне может составлять 50% (в принципе, при некоторых сценариях и все 35% от исходного объёма). Заодно выяснил, что некоторые серверы плюют на робкие попытки прокси попросить закрывать соединение после отсылки данных (пришлось закрывать самостоятельно). Ну и конечно, всё периодически глючит, как же без этого.

К чему я это пишу? А к тому, чтобы похвастаться, да и узнать, а вдруг кому-нибудь это будет интересно. Могу отдать, вплоть до исходников. Может и поправите ошибки.  Поэтому и не выкладываю программу сразу. Ибо реально есть ещё проблемы, с которыми можно жить, но лучше не стоит.

Конечно же, можно было бы взять что-нибудь готовое, но это совершенно неинтересно. Написать что-нибудь самому, очень полезно для развития. При этом, как я уже писал, с оценкой времени всё туманно, так что как оценить пользу/вред от этого совершенно непонятно.