<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;AkMBSXwzeip7ImA9WhRVEUU.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356</id><updated>2012-01-10T13:40:58.282+04:00</updated><category term="ruby" /><category term="венгерская нотация" /><category term="всякое" /><category term="tornado" /><category term="параллельные вычисления" /><category term="twisted" /><category term="web" /><category term="thin" /><category term="VirtualBox" /><category term="perl" /><category term="программы" /><category term="locale" /><category term="wince" /><category term="оптимизация" /><category term="http" /><category term="юмор" /><category term="IDE" /><category term="размышления" /><category term="отладка" /><category term="InnoDB" /><category term="C++" /><category term="селекторы" /><category term="pda" /><category term="MFC" /><category term="bdb" /><category term="WriteFile" /><category term="ReadFile" /><category term="python" /><category term="std::locale" /><category term="nginx" /><category term="utf8" /><category term="html" /><category term="mongrel" /><category term="xpath" /><category term="fictionbook" /><category term="Qt" /><category term="gcc" /><category term="базы данных" /><category term="eclipse" /><category term="g++" /><category term="WinAPI" /><category term="stl" /><category term="patch" /><title>Alex Nekipelov Blog</title><subtitle type="html" /><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://blog.nekipelov.net/" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/11644484550750096086</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://1.bp.blogspot.com/-gF40tHGJFbk/TXMfXxe4Z2I/AAAAAAAAADM/Ovx7kQb5p_4/s220/%25D1%258F%2B%25D1%2581%2B%25D1%2581%25D0%25BE%25D0%25B1%25D0%25B0%25D0%25BA%25D0%25BE%25D0%25B9%2B%25D0%25BC%25D0%25B8%25D0%25BD%25D0%25B8.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>24</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/AlexNekipelovBlog" /><feedburner:info uri="alexnekipelovblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;AkMBSX07fSp7ImA9WhRVEUU.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356.post-8081802697010211857</id><published>2012-01-10T13:39:00.000+04:00</published><updated>2012-01-10T13:40:58.305+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-10T13:40:58.305+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="C++" /><title>ресурс dev.wikitt.com</title><content type="html">&lt;p&gt;При создании этого блога я думал, что не буду писать о банальных вещах для начинающих. Об этом и так на каждом углу пишут. Однако статьи для профессионалов, да еще интересные, почему-то в голову не лезут :-)&lt;/p&gt;

&lt;p&gt;Также я давно задумывался о том, что пусть и для начинающих написано много, однако все ли написанное стоит читать? Частенько для начинающих пишут такие же начинающие, поэтому с ошибками. Да и более опытные программисты тоже могут ошибаться. Также написанное где-то в блоге некоторое время назад может перестать быть актуальным на сегодняшний день. Ведь меняется язык, меняются процессоры и операционные системы&amp;hellip; В общем пришел к тому, что хотелось бы ресурс, подобный wikipedia, но для программистов. Ну и благодаря наличию свободного времени в эти праздники, сделал сайтик &lt;a href="http://dev.wikitt.com"&gt;http://dev.wikitt.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Вот, что есть на данный момент:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://dev.wikitt.com/wiki/C++/%D0%9E%D0%BF%D1%82%D0%B8%D0%BC%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F-%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC-%D0%BD%D0%B0-%D1%8F%D0%B7%D1%8B%D0%BA%D0%B5-C++"&gt;Советы по оптимизации программ на языке C++&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Написал основное, что пришло в голову. Пока не добрался до STL и всяких сортировок&amp;hellip; Как будет время, дополню.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://dev.wikitt.com/wiki/C++/%D0%98%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%B8%D0%B4%D0%B8%D0%BE%D0%BC%D1%8B-pimpl-%D1%81%D0%BE%D0%B2%D0%BC%D0%B5%D1%81%D1%82%D0%BD%D0%BE-%D1%81-%D1%83%D0%BC%D0%BD%D1%8B%D0%BC%D0%B8-%D1%83%D0%BA%D0%B0%D0%B7%D0%B0%D1%82%D0%B5%D0%BB%D1%8F%D0%BC%D0%B8"&gt;Использование идиомы pimpl совместно с умными указателями&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Несколько раз встречал на формах сообщения о подобной проблеме. Поэтому решил описать решение и причину.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://dev.wikitt.com/wiki/C++/%D0%A7%D1%82%D0%BE-%D0%BF%D1%80%D0%B5%D0%B4%D0%BF%D0%BE%D1%87%D1%82%D0%B8%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%B5%D0%B9:-%D1%81%D1%81%D1%8B%D0%BB%D0%BA%D0%B0-%D0%B8%D0%BB%D0%B8-%D1%83%D0%BA%D0%B0%D0%B7%D0%B0%D1%82%D0%B5%D0%BB%D1%8C"&gt;Что предпочтительней: ссылка или указатель?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Описаны больше свои собственные соображения на этот счет. Хотя коллеги почему-то предпочитают больше оперировать указателями :&amp;ndash;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://dev.wikitt.com/wiki/C++/%D0%9D%D0%B5-%D0%B7%D0%BB%D0%BE%D1%83%D0%BF%D0%BE%D1%82%D1%80%D0%B5%D0%B1%D0%BB%D1%8F%D0%B9%D1%82%D0%B5-%D0%BF%D0%B5%D1%80%D0%B5%D0%B3%D1%80%D1%83%D0%B7%D0%BA%D0%BE%D0%B9-%D0%BE%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80%D0%BE%D0%B2"&gt;Почему не следует использовать перегрузку операторов&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;На работе мне как-то встретился класс, у которого перегружены все возможные операторы. И перегружены они совершенно для разных типов, даже шаблонные есть.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://dev.wikitt.com/wiki/C++/%D0%9D%D0%B5-%D0%B7%D0%BB%D0%BE%D1%83%D0%BF%D0%BE%D1%82%D1%80%D0%B5%D0%B1%D0%BB%D1%8F%D0%B9%D1%82%D0%B5-%D0%BE%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80%D0%B0%D0%BC%D0%B8-%D0%BF%D1%80%D0%B5%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F-%D1%82%D0%B8%D0%BF%D0%BE%D0%B2"&gt;Почему не стоит использовать операторы преобразования типов&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;  Опять же из опыта работы, приходилось иметь дело вот с таким кодом:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
  template&amp;lt;typename TYPE&amp;gt; void Assign(const TYPE&amp;amp; tValue)
  {
    Realloc(sizeof(TYPE));
    *(TYPE*)m_ptr = tValue;
  }
  operator void* () { return (void*)m_ptr; }
  operator long* () { return (long*)m_ptr; }
  operator double* () { return ((double*)m_ptr); }
  operator int* () { return ((int*)m_ptr); }
  operator short* () { return ((short*)m_ptr); }
  operator char* () { return ((char*)m_ptr); }
  operator UCHAR* () { return ((UCHAR*)m_ptr); }
  operator LPCSTR () { return ((LPCSTR)m_ptr); }
  operator DATE_FORMAT* () { return ((DATE_FORMAT*)m_ptr); }
  operator TIME_FORMAT* () { return ((TIME_FORMAT*)m_ptr); }
  operator SOFT_REF* () { return ((SOFT_REF*)m_ptr); }
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Все желающие поделиться полезной информацией, приглашаются :-)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8536094954863042356-8081802697010211857?l=blog.nekipelov.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AlexNekipelovBlog/~4/Iv9azSjwVkE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/8081802697010211857/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://blog.nekipelov.net/2012/01/blog-post.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/8081802697010211857?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/8081802697010211857?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AlexNekipelovBlog/~3/Iv9azSjwVkE/blog-post.html" title="ресурс dev.wikitt.com" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/11644484550750096086</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://1.bp.blogspot.com/-gF40tHGJFbk/TXMfXxe4Z2I/AAAAAAAAADM/Ovx7kQb5p_4/s220/%25D1%258F%2B%25D1%2581%2B%25D1%2581%25D0%25BE%25D0%25B1%25D0%25B0%25D0%25BA%25D0%25BE%25D0%25B9%2B%25D0%25BC%25D0%25B8%25D0%25BD%25D0%25B8.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nekipelov.net/2012/01/blog-post.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEECRX87eip7ImA9WhRSEEU.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356.post-4584028385485035186</id><published>2011-11-12T12:29:00.001+04:00</published><updated>2011-11-12T12:31:04.102+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-12T12:31:04.102+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Qt" /><category scheme="http://www.blogger.com/atom/ns#" term="C++" /><title>Qt, resize и нехватка памяти</title><content type="html">&lt;p&gt;Недавно обнаружил в Qt интересный момент. Как известно, исключения в ней не используются. Они объясняют это ростом размера библиотеки, снижением скорости и не совместимостью с главным циклом приложения. Хорошо это или плохо, не важно. Важно то, что с этой библиотекой приходится работать. И еще важно, что исключительные ситуации бывают, без них не обойтись.&lt;/p&gt;

&lt;p&gt;Так вот, я как то не задумывался о проблеме исключений в Qt. Но недавно наткнулся на проблему: программа гадила в память и валилась. Гадила она в память, в которую гадить вроде бы не должна:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
QVector&amp;lt;char&amp;gt; buff;
buff.resize( buffSize );
memcpy( src, buff.data(), buffSize );
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Размер buffSize что-то около 200 Мб. Вроде бы и не много. Но когда программа работает долгое время, память фрагментируется, одного куска размером 200 Мб может и не быть. По аналогии с STL я привык, что это корректный код. При нехватке памяти будет сгенерировано исключение, которое будет поймано и обработано, или обработчик этой проблемы освободит память. И когда вылезла беда, стал разбираться&amp;hellip; Для выделения памяти в Qt используется аналогичные ANSI-C фукнциям &lt;code&gt;qMalloc&lt;/code&gt;, &lt;code&gt;qRealloc&lt;/code&gt;, &lt;code&gt;qFree&lt;/code&gt;. При невозможности выделить память, они возвращают &lt;code&gt;NULL&lt;/code&gt;. Только вот &lt;code&gt;resize&lt;/code&gt; не возвращает результата, и исключение не генерируется. Получается, что указанный выше код корректен в STL, но не корректен в случае контейнеров Qt. Подобная же проблема имеется и с классом &lt;code&gt;QByteArray&lt;/code&gt;, и вероятно со многими другими.&lt;/p&gt;

&lt;p&gt;А самое смешное, вот что говорят в рассылке на эту тему:&lt;/p&gt;

&lt;blockquote&gt;&lt;blockquote&gt;&lt;p&gt;A short and simple question.&lt;/p&gt;

&lt;p&gt;How an application can detect failure in
 QByteArray::resize(int newSize)
method, since resize() is a void function?&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;You can&amp;rsquo;t.&lt;/p&gt;

&lt;p&gt;If memory allocation fails, you&amp;rsquo;re out of luck. You should crash your
application at this point and help the system free up memory for other
applications.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Источник: &lt;a href="http://lists.trolltech.com/qt-interest/2008-10/thread00114-0.html"&gt;http://lists.trolltech.com/qt-interest/2008-10/thread00114-0.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;По моему, валится не обязательно, т.к. как раз для этого придумали &lt;code&gt;set_new_handler&lt;/code&gt;, который в моем случае наверняка нашел бы дополнительную память, выгрузив кое-какие данные.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8536094954863042356-4584028385485035186?l=blog.nekipelov.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AlexNekipelovBlog/~4/7V1VPbKkcxA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/4584028385485035186/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://blog.nekipelov.net/2011/11/qt-resize.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/4584028385485035186?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/4584028385485035186?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AlexNekipelovBlog/~3/7V1VPbKkcxA/qt-resize.html" title="Qt, resize и нехватка памяти" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/11644484550750096086</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://1.bp.blogspot.com/-gF40tHGJFbk/TXMfXxe4Z2I/AAAAAAAAADM/Ovx7kQb5p_4/s220/%25D1%258F%2B%25D1%2581%2B%25D1%2581%25D0%25BE%25D0%25B1%25D0%25B0%25D0%25BA%25D0%25BE%25D0%25B9%2B%25D0%25BC%25D0%25B8%25D0%25BD%25D0%25B8.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nekipelov.net/2011/11/qt-resize.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEYDQnsyfyp7ImA9WhRSEU0.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356.post-3310454867374843677</id><published>2011-11-11T11:07:00.001+04:00</published><updated>2011-11-12T17:56:13.597+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-12T17:56:13.597+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="http" /><category scheme="http://www.blogger.com/atom/ns#" term="tornado" /><category scheme="http://www.blogger.com/atom/ns#" term="twisted" /><category scheme="http://www.blogger.com/atom/ns#" term="nginx" /><category scheme="http://www.blogger.com/atom/ns#" term="mongrel" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="thin" /><title>Сравнение http серверов приложений</title><content type="html">&lt;p&gt;Продолжу тему http серверов. На этот раз про сервера приложений для ruby и python. С другими языками я практически не дружу (не считая c++, конечно же).&lt;p/&gt;

&lt;p&gt;
Их много, все они разные, и главное отличие - скорость обработки запросов. Еще, конечно же, важно назначение http сервера. К примеру назначение http сервера &lt;b&gt;Mongrel&lt;/b&gt;&amp;nbsp;и &lt;b&gt;Thin&lt;/b&gt;&amp;nbsp;- запуск приложений, написанных на языке ruby, а &lt;b&gt;Tornado&lt;/b&gt; или &lt;b&gt;Twisted&lt;/b&gt; для приложений, написанных на python. Конечно их можно использовать и для раздачи статических файлов... но я не советую :-)&lt;p/&gt;

&lt;p&gt;
Из-за отсутствия нормальной реализации многопоточности в этих языках (и наличия GIL), http сервера приложений способны обслуживать клиентов только в один поток. Поэтому, чтобы заставить их использовать несколько процессоров, запускают несколько экземпляров http серверов, перед ними выставляя балансировщик (apache, nginx, lighttpd).&lt;p/&gt;


&lt;p&gt;Основная задача, которую я хочу выполнить: узнать максимальное количество запросов в секунду, на которые способны указанные сервера приложений. Они были выбраны как самые быстрые (не считая Mongrel, конечно же). Если вы знаете более быстрые сервера приложений для ruby или python, пожалуйста, сообщите мне об этом. Методика тестирования заключается в создании минимального приложения, которое будет отдавать строку "&lt;b&gt;Hello World&lt;/b&gt;". Сначала я хотел делать второй этап теста и отдавать больший объем данных, но судя по результатам, это не значительно влияет на результаты, поэтому их не привожу. Тестовый стенд: AMD Phenom(tm) II X4 940, 8 Gb RAM, Debian Squeeze, сборка для AMD64. Все тексты запускались несколько раз, чтобы убедится в стабильности результатов. Для теста используется ab, первый тест выполняется с аргументом -c 1, второй -c 100 (это количество параллельных запросов). При запуске я привязываю приложение к определенному процессору, чтобы оно не скакало с одного на другой. Полный лог вывода к сожалению не помещается (видимо на Blogger имеется ограничение на размер поста), исходные тексты тестов можно найти в конце текста.&lt;/p&gt;

&lt;p&gt;Для начала о сервере Mongrel: &lt;a href="http://ru.wikipedia.org/wiki/Mongrel"&gt;http://ru.wikipedia.org/wiki/Mongrel&lt;/a&gt;. Помимо написанного в википедии добавлю, что он практически полностью написан на ruby, за исключением парсера http запросов (эта часть написана на C). Как уже указано в википедии, до недавнего времени достаточно нагруженный проект Twitter использовал Mongrel. Вот из статейки об архитектуре Twitter &lt;a href="http://highscalability.com/scaling-twitter-making-twitter-10000-percent-faster"&gt;http://highscalability.com/scaling-twitter-making-twitter-10000-percent-faster&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
Mongrel - hybrid Ruby/C HTTP server designed to be small, fast, and secure
&lt;/blockquote&gt;

&lt;p&gt;На тот момент twitter использовали примерно 350 000 пользователей, уже кучу серверов, и Mongrel справлялся со своей задачей. Надо отметить, что во время второго теста с 100 клиентов, время от времени ab жаловался на "apr_socket_recv: Connection timed out (110)", что не очень хорошо. Вот, на что он способен (напоминаю, что смотреть нужно значение "Requests per second"):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
Concurrency Level:      1
Time taken for tests:   36.468 seconds
Requests per second:    2742.11 [#/sec] (mean)
Time per request:       0.365 [ms] (mean)
Time per request:       0.365 [ms] (mean, across all concurrent requests)
Transfer rate:          353.47 [Kbytes/sec] received
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;
Concurrency Level:      100
Time taken for tests:   26.562 seconds
Requests per second:    3764.78 [#/sec] (mean)
Time per request:       26.562 [ms] (mean)
Time per request:       0.266 [ms] (mean, across all concurrent requests)
Transfer rate:          485.30 [Kbytes/sec] received
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Теперь посмотрим на Thin. Он использует EventMachine, который частично написан на C++. Соответственно используется асинхронная обработка запросов. Парсер запросов также написан на C. Каких-либо историй успехов найти не смог (вероятно плохо искал). Вот его результаты:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
Concurrency Level:      1
Time taken for tests:   34.807 seconds
Requests per second:    2872.98 [#/sec] (mean)
Time per request:       0.348 [ms] (mean)
Time per request:       0.348 [ms] (mean, across all concurrent requests)
Transfer rate:          412.43 [Kbytes/sec] received
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;
Concurrency Level:      100
Time taken for tests:   16.325 seconds
Requests per second:    6125.52 [#/sec] (mean)
Time per request:       16.325 [ms] (mean)
Time per request:       0.163 [ms] (mean, across all concurrent requests)
Transfer rate:          879.35 [Kbytes/sec] received
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Thin явно быстрее Mongrel при увеличении количества параллельных запросов. Основное преимущество Thin в том, что его можно использовать для реализации Comet сервера.&lt;/p&gt;

&lt;p&gt;Теперь перейдем к python. Честно говоря, я и с этим языком практически не дружу. Поэтому даже не знаю, кто в стане python является самым быстрым. Наиболее часто я слышу про Tornado и Twisted. Для начала о Twisted. Большей частью написан на python, но местами, разумеется, на C. Является не сервером приложений, а событийно-ориентированным фреймворком для разработки серверов. Т.е. то, чем является EventMachine для ruby. Сразу замечу, что результаты не впечатляют. Возможно потому, что парсер запросов не написан на C :-) Во время тестирования ошибка "apr_socket_recv: Connection refused (111)" выскакивала при отсутствии параллельных запросов.
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
Concurrency Level:      1
Time taken for tests:   70.951 seconds
Requests per second:    1409.43 [#/sec] (mean)
Time per request:       0.710 [ms] (mean)
Time per request:       0.710 [ms] (mean, across all concurrent requests)
Transfer rate:          202.33 [Kbytes/sec] received
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;
Concurrency Level:      100
Time taken for tests:   31.263 seconds
Requests per second:    3198.64 [#/sec] (mean)
Time per request:       31.263 [ms] (mean)
Time per request:       0.313 [ms] (mean, across all concurrent requests)
Transfer rate:          459.18 [Kbytes/sec] received
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Теперь Tornado. Был создан в компании Friendfeed и предоставлен на суд общественности после приобретения последней компанией Facebook. Они написали Tornado как раз потому, что Twisted имеет некоторые проблемы с быстродействием, источник: &lt;a href="http://bret.appspot.com/entry/tornado-web-server"&gt;http://bret.appspot.com/entry/tornado-web-server&lt;/a&gt;. Судя по результатам, у них это получилось.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
Concurrency Level:      1
Time taken for tests:   50.786 seconds
Requests per second:    1969.03 [#/sec] (mean)
Time per request:       0.508 [ms] (mean)
Time per request:       0.508 [ms] (mean, across all concurrent requests)
Transfer rate:          334.58 [Kbytes/sec] received
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;
Concurrency Level:      100
Time taken for tests:   19.708 seconds
Requests per second:    5074.07 [#/sec] (mean)
Time per request:       19.708 [ms] (mean)
Time per request:       0.197 [ms] (mean, across all concurrent requests)
Transfer rate:          862.20 [Kbytes/sec] received
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Признаться, я приятно удивлен тем, что ruby сервера справляются лучше, чем python. Но возможно причина в том, что разбор запросов в случае ruby осуществляется на C. Я не ставил целью сравнивать между собой эти два прекрасных языка программирования. Моя цель в том, чтобы показать общую картину. Хотя для того, чтобы показать ее полностью, следовало сравнить фреймворки Ruby On Rails и Django. Там все будет значительно худе, в лучшем случае несколько сотен запросов в секунду. Вот презентация: &lt;a href="http://www.scribd.com/doc/51076611/RubyConfUA-Ruby-on-Rails-1000-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%BE%D0%B2-%D0%B2-%D1%81%D0%B5%D0%BA%D1%83%D0%BD%D0%B4%D1%83-%D0%9C%D0%B0%D0%BA%D1%81-%D0%9B%D0%B0%D0%BF%D1%88%D0%B8%D0%BD"&gt;http://www.scribd.com/doc/51076611/RubyConfUA-Ruby-on-Rails-1000-запросов-в-секунду-Макс-Лашин&lt;/a&gt;, где описывается ситуация, что для обработки 1000 запросов в секунду требуется 14 серверов. К сожалению нет деталей, сколько из этих серверов отданы для БД, а сколько для Ruby On Rails. Разумеется это уже не "Hello, world", и вероятно основная нагрузка будет идти на БД. Однако, если судить по архитектуре других проектов, серверов слишком много для такой нагрузки.&lt;/p&gt;

&lt;p&gt;Мне кажется, что подобные языки не предназначены для разработки http серверов, где приходится обслуживать большое количество клиентов. Я пишу именно http серверов, а не http приложений. В любое приложение на C или C++ легко встраивается почти любой язык программирования. И явно такие сервера должны быть. Интересно, почему они не пользуются популярностью? Для сравнения, вот, на что способен nginx, работая одним воркером:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
Concurrency Level:      1
Time taken for tests:   17.761 seconds
Requests per second:    5630.18 [#/sec] (mean)
Time per request:       0.178 [ms] (mean)
Time per request:       0.178 [ms] (mean, across all concurrent requests)
Transfer rate:          1264.59 [Kbytes/sec] received
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;
Concurrency Level:      100
Time taken for tests:   3.889 seconds
Requests per second:    25715.85 [#/sec] (mean)
Time per request:       3.889 [ms] (mean)
Time per request:       0.039 [ms] (mean, across all concurrent requests)
Transfer rate:          5776.02 [Kbytes/sec] received
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;При этом у nginx задача чуть сложнее, я не стал писать к нему модуль, поэтому nginx отдает файл. Результаты для 100 клиентов впечатляют. Я несколько раз перепроверял, но ошибки нет. Хотя если вдуматься, что такое 100 000 раз открыть и отправить какой-то там файлик? Это займет пол секунды (специально проверил). Основной расход ресурсов уходит на коммуникацию. Раз уж перешел к отдаче файлов, в последнее время часто упоминается &lt;b&gt;yaws&lt;/b&gt;, написанный на &lt;b&gt;Erlang&lt;/b&gt;. Встретил даже вот такие восхищенные строки:&lt;/p&gt;

&lt;blockquote&gt;
Yaws (Yet Another Web Server) - web сервер написанный на языке Erlang. На языке, который по праву считается крайне производительным. Тоже самое можно сказать и об самом web сервере: по сравнению с apache2, yaws - просто реактивный.&lt;br /&gt;

http://the-bosha.ru/2010/08/30/yaws-lyogkiy-web-server-na-erlang/
&lt;/blockquote&gt;

&lt;p&gt;Ну и множество других восторженных отзывов. Пройти мимо просто нельзя. Ради этого даже поставил yaws из репозитария wheezy, чтобы тестировать последнюю версию. Вот, что я получил:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
Server Software:        Yaws
Concurrency Level:      1
Time taken for tests:   33.808 seconds
Requests per second:    2957.89 [#/sec] (mean)
Time per request:       0.338 [ms] (mean)
Time per request:       0.338 [ms] (mean, across all concurrent requests)
Transfer rate:          652.82 [Kbytes/sec] received
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;
Concurrency Level:      100
Time taken for tests:   24.427 seconds
Failed requests:        171
   (Connect: 0, Receive: 57, Length: 57, Exceptions: 57)
Write errors:           0
Total transferred:      22587118 bytes
HTML transferred:       1998860 bytes
Requests per second:    4093.88 [#/sec] (mean)
Time per request:       24.427 [ms] (mean)
Time per request:       0.244 [ms] (mean, across all concurrent requests)
Transfer rate:          903.02 [Kbytes/sec] received
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;В глаза бросается строка &lt;i&gt;(Connect: 0, Receive: 57, Length: 57, Exceptions: 57)&lt;/i&gt;. И сколько бы я не запускал ab, ошибки вылезают. Видимо 100 запросов на один сервер, многовато. На реактивный он явно не похож.&lt;/p&gt;


&lt;h4&gt;UPDATE&lt;/h4&gt;

&lt;p&gt;По совету &lt;a href="http://www.blogger.com/profile/07741066262220456994"&gt;Viacheslav Biriukov&lt;/a&gt; повторил тест на gunicorn для python. Разбираться, как он реализован, пока нет времени. Вот его результаты:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
Concurrency Level:      1
Time taken for tests:   37.928 seconds
Requests per second:    2636.57 [#/sec] (mean)
Time per request:       0.379 [ms] (mean)
Time per request:       0.379 [ms] (mean, across all concurrent requests)
Transfer rate:          424.84 [Kbytes/sec] received
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;
Concurrency Level:      100
Time taken for tests:   19.764 seconds
Requests per second:    5059.64 [#/sec] (mean)
Time per request:       19.764 [ms] (mean)
Time per request:       0.198 [ms] (mean, across all concurrent requests)
Transfer rate:          815.27 [Kbytes/sec] received
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;При отсутствии конкуренции он показал себя значительно лучше Tornado и Twisted.&lt;/p&gt;

&lt;h3&gt;Итоговый результат в виде картинки:&lt;/h3&gt;

    &lt;script type="text/javascript" src="https://www.google.com/jsapi"&gt;&lt;/script&gt;
    &lt;script type="text/javascript"&gt;
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = new google.visualization.DataTable();
        data.addColumn('string', 'Конкуренция');
        data.addColumn('number', 'Mongrel');
        data.addColumn('number', 'Thin');
        data.addColumn('number', 'Twisted');
        data.addColumn('number', 'Tornado');
        data.addColumn('number', 'gunicorn');
        data.addColumn('number', 'Yaws');
        data.addColumn('number', 'Ngixn');
        data.addRows(2);
        data.setValue(0, 0, '1 клиент');
        data.setValue(0, 1, 2742);
        data.setValue(0, 2, 2872);
        data.setValue(0, 3, 1409);
        data.setValue(0, 4, 1969);
        data.setValue(0, 5, 2636);
        data.setValue(0, 6, 2957);
        data.setValue(0, 7, 5630);
        data.setValue(1, 0, '100 клиентов');
        data.setValue(1, 1, 3764);
        data.setValue(1, 2, 6125);
        data.setValue(1, 3, 3198);
        data.setValue(1, 4, 5074);
        data.setValue(1, 5, 5059);
        data.setValue(1, 6, 4093);
        data.setValue(1, 7, 25715);

        var chart = new google.visualization.ColumnChart(document.getElementById('chart'));
        chart.draw(data, {width: 600, height: 600, title: 'HTTP Performance',
                          vAxis: {title: 'Запросов/сек', titleTextStyle: {color: 'red'}}
                         });
      }
    &lt;/script&gt;

&lt;div id="chart"&gt;&lt;/div&gt;


&lt;p&gt;Ну а теперь исходные тексты.&lt;/p&gt;

&lt;h5&gt;Mongrel:&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;
require 'mongrel'

class HelloHandler &amp;lt; Mongrel::HttpHandler
        def process(request, response)
                response.start(200) do |head,out|
                        head['content-type'] = 'text/html'
                        out &amp;lt;&amp;lt; '&amp;lt;p&amp;gt;Hello World!&amp;lt;/p&amp;gt;'
                end
        end
end

h = Mongrel::HttpServer.new("0.0.0.0", "3000")
h.register("/hello", HelloHandler.new)
&lt;/code&gt;&lt;/pre&gt;

&lt;h5&gt;Thin&lt;/h5&gt;

&lt;pre&gt;&lt;code  class="ruby"&gt;
require 'thin'

app = proc do |env|
# Response body has to respond to each and yield strings
# See Rack specs for more info: http://rack.rubyforge.org/doc/files/SPEC.html
body = ['&amp;lt;p&amp;gt;&amp;lt;p&amp;gt;Hello World!&amp;lt;/p&amp;gt;']

[
    200,                                        # Status code
    { 'Content-Type' =&amp;gt; 'text/html' },          # Reponse headers
    body                                        # Body of the response
]
end

run app
&lt;/code&gt;&lt;/pre&gt;

&lt;h5&gt;Twisted&lt;/h5&gt;

&lt;pre&gt;&lt;code&gt;
# -*- coding: utf-8 -*-
from twisted.web import server, resource
from twisted.internet import reactor

class Simple(resource.Resource):
    isLeaf = True
    def render_GET(self, request):
        return "&amp;lt;p&amp;gt;Hello world!&amp;lt;/p&amp;gt;"

site = server.Site(Simple())
reactor.listenTCP(3000, site)
reactor.run()
&lt;/code&gt;&lt;/pre&gt;

&lt;h5&gt;Tornado&lt;/h5&gt;

&lt;pre&gt;&lt;code class="python"&gt;
# -*- coding: utf-8 -*-
import tornado.httpserver
import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
        def get(self):
                self.write("&amp;lt;p&amp;gt;Hello, world&amp;lt;p&amp;gt;")

if __name__ == "__main__":
        application = tornado.web.Application([
                (r"/hello", MainHandler),
        ])
        http_server = tornado.httpserver.HTTPServer(application)
        http_server.listen(3000)
        tornado.ioloop.IOLoop.instance().start()
&lt;/code&gt;&lt;/pre&gt;


&lt;h5&gt;gunicorn&lt;/h5&gt;

&lt;pre&gt;&lt;code class="python"&gt;
# -*- coding: utf-8 -
from wsgiref.validate import validator

#@validator
def app(environ, start_response):
    """Simplest possible application object"""
    data = '&amp;lt;p&amp;gt;Hello, World&amp;lt;/p&amp;gt;'
    status = '200 OK'
    response_headers = [
        ('Content-type','text/plain'),
        ('Content-Length', str(len(data)))
    ]
    start_response(status, response_headers)
    return iter([data])
&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8536094954863042356-3310454867374843677?l=blog.nekipelov.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AlexNekipelovBlog/~4/3j9BdiRvQAI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/3310454867374843677/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://blog.nekipelov.net/2011/11/http.html#comment-form" title="Комментарии: 2" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/3310454867374843677?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/3310454867374843677?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AlexNekipelovBlog/~3/3j9BdiRvQAI/http.html" title="Сравнение http серверов приложений" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/06482882049372705141</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total><feedburner:origLink>http://blog.nekipelov.net/2011/11/http.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUYNRH06fyp7ImA9WhZTGE4.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356.post-8861104642982801180</id><published>2011-03-23T02:39:00.000+03:00</published><updated>2011-03-23T02:39:55.317+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-23T02:39:55.317+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="WinAPI" /><title>Зависание при переключении раскладки</title><content type="html">Об этой проблеме я хотел написать еще год назад, да что-то так и не написал. Совсем не до этого было.&lt;br /&gt;
&lt;br /&gt;
Началось все с того, что коллега начал жаловаться, после моих изменений у него начала зависать программа при переключении раскладки. Зависание было иногда и не на долго. Потом появился еще один с такой же жалобой. Ни одна попытка воспроизвести не увенчалась успехом. Снятие дампа, трассировка, тоже не помогли. Через пол года этих "жалобщиков" стало еще больше и деваться стало некуда, пришлось разбираться. Порывшись в интернете я выяснил, что подобная проблема возникает в программах Miranda, Punto Switcher и других. И возникает она после установки Internet Explorer 7.0, который несет в себе так называемые "Дополнительные текстовые службы". После их установки зависание и начинается. А после отключения прекращается. Однако после отключения их любимый IE сам начинает вести себя не адекватно, или перестает переключать раскладку. В общем это не вариант. Еще один вариант исправления - это убрать индикатор раскладки. Но клиентам ни один из вариантов не подойдет. &lt;br /&gt;
&lt;br /&gt;
Пришлось мне сделать очередной spanshot в виртуальной машине и ставить этот самый IE7. Spanshot разумеется для того, чтобы после исправления проблемы вернуть "любимый" IE6.&lt;br /&gt;
&lt;br /&gt;
После долгой и нудной отладки выяснилось, что зависание происходит только при запуске определенного потока. После еще более нудной отладки выяснилось, что виновато скрытое окно, которое создается в этом потоке. Точнее проблема проявляется только после создания этого окна, именно это и было мое изменение. Но окно нужно для того, чтобы работали таймеры. В конце концов нашел гадкое место, это вызов Sleep. Это сейчас я нашел в MSDN вот такие строки:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;Code that directly or indirectly creates windows (for example, DDE and COM CoInitialize). If a thread creates any windows, it must process messages. Message broadcasts are sent to all windows in the system. If you have a thread that uses Sleep with infinite delay, the system will deadlock.&lt;br /&gt;
&lt;/blockquote&gt;&lt;br /&gt;
Еще пару лет назад про окна ничего не было написано. Хотя может быть я смотрел устаревший MSDN...&lt;br /&gt;
&lt;br /&gt;
В общем, будьте осторожны. Если параллельный поток создает окно, очень нежелательно использовать в нем вызовы, блокирующие обработку сообщений. Иначе, в случае рассылки сообщения всем окнам, ваше приложение будет "подвисать".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8536094954863042356-8861104642982801180?l=blog.nekipelov.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AlexNekipelovBlog/~4/Y5HnqCqteA0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/8861104642982801180/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://blog.nekipelov.net/2011/03/blog-post.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/8861104642982801180?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/8861104642982801180?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AlexNekipelovBlog/~3/Y5HnqCqteA0/blog-post.html" title="Зависание при переключении раскладки" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/11644484550750096086</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://1.bp.blogspot.com/-gF40tHGJFbk/TXMfXxe4Z2I/AAAAAAAAADM/Ovx7kQb5p_4/s220/%25D1%258F%2B%25D1%2581%2B%25D1%2581%25D0%25BE%25D0%25B1%25D0%25B0%25D0%25BA%25D0%25BE%25D0%25B9%2B%25D0%25BC%25D0%25B8%25D0%25BD%25D0%25B8.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nekipelov.net/2011/03/blog-post.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk4CQH88eyp7ImA9WhZTFEU.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356.post-8880568664392975241</id><published>2011-03-19T00:49:00.000+03:00</published><updated>2011-03-19T00:49:21.173+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-19T00:49:21.173+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="WinAPI" /><category scheme="http://www.blogger.com/atom/ns#" term="WriteFile" /><category scheme="http://www.blogger.com/atom/ns#" term="VirtualBox" /><category scheme="http://www.blogger.com/atom/ns#" term="ReadFile" /><title>ReadFile/WriteFile ERROR_INVALID_ARGUMENT</title><content type="html">Сегодня столкнулся с интересной проблемой. Программа записывала небольшой блок данных, около 20 мегабайт, после читала и читалось уже совсем не то, что было записано.&lt;br /&gt;
&lt;br /&gt;
Как это часто бывает, корректность записи и чтения никто не проверял. Вставив соответствующие проверки я увидел, что ни запись, ни чтение не осуществляются вообще. GetLastError стабильно возвращает код ошибки 87: &lt;strong&gt;ERROR_INVALID_ARGUMENT&lt;/strong&gt; или "Параметр задан неверно". А все что прочиталось - жалкие остатки из буфера для записи. При том, что этот код точно работал и никто его не менял. И ограничение на размер буфера для функций &lt;strong&gt;ReadFile&lt;/strong&gt; и &lt;strong&gt;WriteFile&lt;/strong&gt; составляет 32 мегабайта.&lt;br /&gt;
&lt;br /&gt;
После некоторых разбирательств выяснилось, что проблема проявляется только при записи на сетевой диск, точнее &lt;strong&gt;Shared Folder&lt;/strong&gt; сделанные с помощью &lt;strong&gt;VirtualBox&lt;/strong&gt;.&lt;br /&gt;
&lt;br /&gt;
В общем, на &lt;strong&gt;Shared Folder&lt;/strong&gt;, сделанный с помощью &lt;strong&gt;VirtualBox&lt;/strong&gt; нельзя выполнять вызовы WinAPI &lt;strong&gt;ReadFile&lt;/strong&gt; и &lt;strong&gt;WriteFile&lt;/strong&gt; передавая буфер больше 16 мегабайт за раз.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8536094954863042356-8880568664392975241?l=blog.nekipelov.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AlexNekipelovBlog/~4/SDBagwWLhbE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/8880568664392975241/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://blog.nekipelov.net/2011/03/readfilewritefile-errorinvalidargument.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/8880568664392975241?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/8880568664392975241?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AlexNekipelovBlog/~3/SDBagwWLhbE/readfilewritefile-errorinvalidargument.html" title="ReadFile/WriteFile ERROR_INVALID_ARGUMENT" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/11644484550750096086</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://1.bp.blogspot.com/-gF40tHGJFbk/TXMfXxe4Z2I/AAAAAAAAADM/Ovx7kQb5p_4/s220/%25D1%258F%2B%25D1%2581%2B%25D1%2581%25D0%25BE%25D0%25B1%25D0%25B0%25D0%25BA%25D0%25BE%25D0%25B9%2B%25D0%25BC%25D0%25B8%25D0%25BD%25D0%25B8.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nekipelov.net/2011/03/readfilewritefile-errorinvalidargument.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0UARHkzeSp7ImA9Wx9aE0U.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356.post-4646452343696647512</id><published>2011-03-06T08:27:00.000+03:00</published><updated>2011-03-06T08:27:25.781+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-06T08:27:25.781+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="http" /><title>Как написать свой http сервер</title><content type="html">Слышал мнение, что многие начинающие программисты стремятся написать свою операционную систему. Ну и что греха таить, я сам когда-то хотел попробовать. И даже что-то там понаписал, оно загружалось и что-то могло делать. Разумеется никаких амбициозных планов, просто с целью получше во всем этом разобраться. Но эта тема уже рассмотрена в сотнях различных статей. Недавно, занимаясь уборкой на жестком диске, нашел написанный когда-то простенький http сервер. И подумал, что тема разработки http серверов далеко не так хорошо освещена. И это тоже может быть интересным. Я хоть и не много, но кое-что знаю. Может кому-то окажется полезным, вопросы об этом я время от времени встречаю.&lt;br /&gt;
&lt;br /&gt;
Итак, я не буду вдаваться в совсем уж мелкие подробности вроде того, что такое сокеты, как работает tcp/ip и уж тем более спускаться на канальный уровень. И полностью описать протокол HTTP тоже не смогу, для этого есть соответствующие RFC: &lt;a href="http://tools.ietf.org/html/rfc1945"&gt;1945&lt;/a&gt; и &lt;a href="http://tools.ietf.org/html/rfc2616"&gt;2616&lt;/a&gt;. Гугл подсказал переводы на русский язык: &lt;a href="http://www.maximano.h1.ru/myrfc.htm"&gt;тут&lt;/a&gt;, &lt;a href="http://lib.ru/WEBMASTER/rfc2068/"&gt;тут (устаревшая версия)&lt;/a&gt; или &lt;a href="http://zeus.sai.msu.ru:7000/nets/semenov/4/45/http4561.shtml"&gt;вот тут&lt;/a&gt;. Переводы я не изучал, если они некорректные, извиняюсь. В примерах я указываю только часть заголовков. Если вам хочется рассмотреть их получше, поможет Webkit Inspector в браузере Google Chrome, или Firebug в браузере Firefox, или DragonFly бразуера Opera. Но лучше всего поставить сниффер и смотреть происходящее с его помощью. Описание даю для пользователей, которые уже более менее представляют, что такое HTTP и как оно работает. Другие вряд-ли сюда забредут и уж тем более соберутся писать http сервер :-)&lt;br /&gt;
&lt;br /&gt;
Начнем сначала. Http клиент обращаясь к серверу посылает запрос вида:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;
    МЕТОД строка_запроса HTTP/Версия
    Поле-Запроса: значение
    Второе-Поле: значение
    ...
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Методы бывают разные: GET, POST, HEAD, OPTIONS, PUT, DELETE... Я опишу только первые три. &lt;strong&gt;GET&lt;/strong&gt; - это получение ресурса. Тут и далее я буду называть строку_запроса ресурсом, или запрашиваемым ресурсом. &lt;strong&gt;POST&lt;/strong&gt; - отправка каких-либо данных на сервер. &lt;strong&gt;HEAD&lt;/strong&gt; аналогичен GET за исключением того, что сервер в ответ на запрос отправляет только заголовок запроса, без данных. Версия может и отсутствовать, тогда считается, что она равна 0.9, и в этом случае в запросе есть только первая строка, а клиенту ответ идет без заголовка, только данные. Запрос завершается двойным переводом строки в символом возврата каретки ("\r\n\r\n") и после него идет тело запроса. В этом случае должно быть указано поле &lt;strong&gt;Content-Length&lt;/strong&gt;, которое и сообщает длину тела. Для GET запроса естественно тела быть не может, зато оно будет в случае запроса методом POST или PUT.&lt;br /&gt;
&lt;br /&gt;
Тело запроса со стороны клиента может быть разным. Если это заполненная форма, то оно представляет из себя набор параметров этой формы и значение. К примеру вот такая форма на html странице:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;
    &amp;lt;form method="POST"&amp;gt;
  &amp;lt;input type="text" name="value1" value="bla-bla" /&amp;gt;
  &amp;lt;input type="hidden" name="value2" value="hidden-bla-bla" /&amp;gt;
    &amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Даст вот такое тело запроса:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;
value1=bla-bla&amp;value2=hidden-bla-bla
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Если пользователь изменит значения, заданные по умолчанию, они естественно изменятся и в теле запроса. В случае, если вместе с формой запроса идет еще и передача прикрепленный файлов, тело будет посложнее. В этом случае оно разбивается на несколько частей, подобно тому, как это делается с электронными письмами:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;
    &amp;lt;form method="POST" enctype="multipart/form-data"&amp;gt;
  &amp;lt;input type="text" name="value1" value="bla-bla" /&amp;gt;
  &amp;lt;input type="hidden" name="value2" value="hidden-bla-bla" /&amp;gt;
  &amp;lt;input name="attached_file" type="file" /&amp;gt;
    &amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Получим тело запроса:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;
--FormBoundary_35WYaqzQvblP0xW
Content-Disposition: form-data; name="value1"

bla-bla

--FormBoundary_35WYaqzQvblP0xW
Content-Disposition: form-data; name="value2"

hidden-bla-bla

--FormBoundary_35WYaqzQvblP0xW
Content-Disposition: form-data; name="attached_file"; filename="image.jpg"
Content-Type: image/jpeg

тут-содержимое-файла
--FormBoundary_35WYaqzQvblP0xWl--
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Способ, которым следует разбирать тело передается в заголовке запроса от клиента, в поле Content-Type. В первом случае будет &lt;strong&gt;Content-Type: application/x-www-form-urlencoded&lt;/strong&gt;, а во втором &lt;strong&gt;Content-Type: multipart/form-data; boundary=--FormBoundary_35WYaqzQvblP0xW&lt;/strong&gt;. Разделителем для второго случае является указанный в &lt;strong&gt;Content-Type&lt;/strong&gt; &lt;strong&gt;boundary&lt;/strong&gt; и символ новой строки и также видно, что клиент передает тип содержимого.&lt;br /&gt;
&lt;br /&gt;
Сервер тоже использует &lt;strong&gt;Content-Type&lt;/strong&gt; для того, чтобы показать клиенту тип содержимого, которое он отдает. К примеру &lt;strong&gt;Content-Type: text/html; charset=utf-8&lt;/strong&gt;. Если клиент - это браузер, то подобный ответ он будет разбирать как html файл. Если там будет &lt;strong&gt;image/png&lt;/strong&gt;, браузер отобразит картинку. Если же там будет что-то, чего браузер отобразить не может, пользователь увидит диалог скачивания файла.&lt;br /&gt;
&lt;br /&gt;
Также клиент передает серверу свои "предпочтения", которые указывает в заголовках &lt;strong&gt;Accept-&lt;/strong&gt;. Его предпочтения могут меняться в зависимости от того, что он ожидает. Если запрос был получен от пользователя путем набора текста в адресной строке, там там будет что-то вроде такого:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;
Accept:application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Charset:UTF-8,*;q=0.5
Accept-Encoding:gzip,deflate,sdch
Accept-Language:ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Тут браузер говорит, что ожидает в первую очередь XML, XHML или HTML файл, но согласен и на обычный текстовый файл, или даже картику, но и все остальное тоже примет. Дальше идет предпочитаемая кодировка. Это значение зависит от настроек браузера. Следущие поля - способы сжатия файла. Ответ может быть сжат указанным способом и клиент сможет его распаковать. Сжатие позволяет экономить трафик. Следующим идет язык. В моем браузере указано предпочитать русский язык, следом идет английской. Разделитель &lt;strong&gt;q=&lt;/strong&gt; указывает на степень предпочтения. Если браузер клиента больше предпочитает &lt;strong&gt;en-US&lt;/strong&gt;, то следует отдать ему файл на английском языке. Именно так некоторые сайты выдают контент на родном для пользователя языке.&lt;br /&gt;
&lt;br /&gt;
А если запрос связан с тем, что браузер при разборе html файла встретил вот такое:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;
&amp;lt;link href="/css/main.css" rel="stylesheet" media="all" type="text/css" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
То его запрос будет содержать уже другой текст:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;
Accept:text/css,*/*;q=0.1
Accept-Charset:UTF-8,*;q=0.5
Accept-Encoding:gzip,deflate,sdch
Accept-Language:ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Т.е. браузер хотел бы получить css файл.&lt;br /&gt;
&lt;br /&gt;
Запрашиваемый у http сервера ресурс должен начинаться с &lt;strong&gt;/путь/еще/файл&lt;/strong&gt;. Разделителями пути выступают слеши, т.к. он всегда использовался как разделитель пути в системах unix. Если ресурс - это программа или скрипт, то ему могут быть переданы дополнительные аргументы. К примеру в вашеуказанной форме метод POST заменим на GET:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;
    &amp;lt;form method="GET"&amp;gt;
  &amp;lt;input type="text" name="value1" value="bla-bla" /&amp;gt;
  &amp;lt;input type="hidden" name="value2" value="hidden-bla-bla" /&amp;gt;
    &amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Теперь браузер не может передать параметры в теле запроса. Поэтому он передает их в URL. И запрашиваемый ресурс будет таким:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;
/path/file?value1=bla-bla&amp;value2=hidden-bla-bla
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Аргументы идут после символа &lt;strong&gt;?&lt;/strong&gt; и также разделяются символом &lt;strong&gt;&amp;&lt;/strong&gt;. Если требуется передать символ ? или &amp; в качестве значения, а также некоторые другие символы, их необходимо заменять на код символа, добавляя символ процента &lt;strong&gt;%&lt;/strong&gt;. Разумеется такой метод запросов можно использовать не только для передачи форм, но и для вызова обработчика на сервере с определенными аргументами. В случае, если ресурс указывает на обычный файл, а не какой-то специализированный обработчик, дополнительные аргументы игнорируются.&lt;br /&gt;
&lt;br /&gt;
Обработчики, принимающие эти аргументы, чаще всего бывают написаны на скриптовых языках. К примеру на perl, php, python или ruby. Хотя там может скрываться программа на любом языке, главное, чтобы сервер мог ее запустить. Стандартный метод запуска - это &lt;strong&gt;CGI&lt;/strong&gt; - Common Gateway Interface. На каждый запрос запускается новый экземпляр программы. Все данные, необходимые CGI программе, передаются через окружение. Т.к. программы старательно жирнеют и толстеют, сейчас запускать программу на каждый запрос является расточительством. Поэтому появился &lt;strong&gt;FastCGI&lt;/strong&gt;, а за ним и &lt;strong&gt;SCGI&lt;/strong&gt;. При использовании последних программа запускается один раз и обрабатывает запросы по мере их поступления крутясь в цикле. Такие программы могут быть быть расположены на любой другой машине в сети, как правило обращение к ним идет по tcp/ip или unix сокетам и запускаются они в нескольких экземплярах. Еще есть возможность использовать мультиплексирование - параллельную обработку нескольких запросов через одно соединение, но к сожалению до сих пор не все хорошо с поддержкой этого мультиплексирования. Ну может быть оно не так уж и нужно, когда можно заранее рассчитать необходимое количество экземпляров и запустить их.&lt;br /&gt;
&lt;br /&gt;
В последнее время частенько используются http сервера, сами написанные на этих скриптовых языках. В таких случаях http сервер, выставленный наружу (front-end) только проксирует запросы серверу приложений (back-end) и раздает статические файлы. Доверять раздачу статических файлов серверам на скриптовых языках рановато :-)&lt;br /&gt;
&lt;br /&gt;
Так как установка TCP/IP соединения занимает достаточно длительное время, т.к. клиенту и серверу необходимо обменяться различными пакетами, придумали возможность поддерживать соединение, это называется &lt;strong&gt;keep-alive&lt;/strong&gt;. Т.е. без keep-alive на каждый запрос создается новое соединение. Если используется Keep-alive, соединение не обрывается, а через него может пойти следующий запрос. Версия HTTP 1.1 всегда использует Keep-Alive, а для версии 1.0 используется поле запроса Keep-Alive. Но можно указать серверу, что соединение можно закрывать, для этого в запрос вставляется поле "Connection: close".&lt;br /&gt;
&lt;br /&gt;
В последние годы набирает популярность так называемый &lt;strong&gt;Ajax&lt;/strong&gt; - асинхронный Javascript. Это когда запрос отсылает не пользователь, а скрипт на странице. Допустим, возможно обращение к ресурсу &lt;strong&gt;/data&lt;/strong&gt;. Если туда обратится пользователь, то ему следует выдать html страницу с запрашиваемыми данными. А если же Javascript, то предпочтительней XML или JSON код. В этом случае к запросу со стороны клиента следует добавлять поле &lt;strong&gt;X-Requested-With: XMLHttpRequest&lt;/strong&gt;. Популярные фреймворки вроде jQuery делают это сами. Обработчик запроса смотрит содержимое этого поля и решает, что отдавать.&lt;br /&gt;
&lt;br /&gt;
Еще одна важная вещь - это кеширование. Вообще по этой теме следует писать отдельную статью. Я опишу только кратко. Кеширование предназначено для того, чтобы снизить нагрузку на сервер - избавить от лишних запросов или хотя-бы уменьшить объем передаваемого трафика. Когда сервер отвечает клиенту, он может передать поле &lt;strong&gt;Last-Modified&lt;/strong&gt; с указанием даты последней модификации. Тогда в следующий раз клиент пришлет запрос с полем &lt;strong&gt;If-Modified-Since&lt;/strong&gt;. Сервер должен проверить, не изменился ли запрашиваемый ресурс. Если изменился, то если даже метод запроса GET, сервер не пересылает данные, а отправляет только заголовок а код ответа устанавливает в &lt;strong&gt;304 (Not Modified)&lt;/strong&gt;.  Дата модификации подходит не всегда, поэтому имеется еще один способ проверки на модифицированность ресусра: передача сервером специального значения и поле &lt;strong&gt;ETag&lt;/strong&gt;, или даже нескольких значений. Эта возможность появилась начиная с версии 1.1. В этом случае клиент добавляет в запрос поле &lt;strong&gt;If-None-Match&lt;/strong&gt;, в котором указывает ранее полученные значения. Чаще всего эти значения являются хешем содержимого. В случае отсутствия изменений клиенту также передается код ответа 304. Еще имеются поля &lt;code&gt;Pragma, Cache-Control, Expires и т.д.&lt;/code&gt;, но для начала хватит и описанного мной :-)&lt;br /&gt;
&lt;br /&gt;
Надо добавить, что с кешированием связаны две крайности: всячески противостоять кешированию или наоборот, кешировать все, что только можно. Истина, как всегда, где-то по середине. Кеширование, и не только в отношении http серверов, очень помогает. Но иногда оно лишнее и приведет к проблемам.&lt;br /&gt;
&lt;br /&gt;
Достаточно важную роль играет поле &lt;strong&gt;Host&lt;/strong&gt;, появившееся в HTTP 1.1. Туда клиент записывает адрес сервера, к которому он обращается. Т.е. если идет обращение по адресу http://www.google.com, то в запросе имеется строка &lt;strong&gt;Host: www.google.com&lt;/strong&gt;. Именно благодаря этому полю работают так называемые "виртуальные сервера", когда на одном физическом с одним ip адресом расположено множество серверов с различными именам. Сервер принимая запрос анализирует содержимое поля и использует ту или иную конфигурацию. И также благодаря наличию этого поля работает так называемое прозрачное кеширование: когда все запросы со стороны клиента принудительно перенаправляются на прокси сервер, который работает в прозрачном режиме (transparent), там обрабатываются (контроль доступа или кеширование) и только потом куда-то уходят. И не факт что уходят они туда, откуда их запросил клиент. К примеру у меня прокси сервер режет рекламу и блокирует часть сайтов, а запросы на статьи в СМИ по возможности преобразует в ссылки на "версию для печати".&lt;br /&gt;
&lt;br /&gt;
При взаимодействии пользователя и web сервера иногда нужно сохранять какие-либо данные пользователя. Например корзину товаров для интернет магазина. Или идентификатор пользователя в рекламной сети. Однажды я спросил у яндекса, как правильно готовить гречневую кашу, так потом меня не меньше месяца преследовал яндекс директ предлагая различные рецепты. Для этого предназначены Cookie. Однажды сервер выдает клиенту в заголовке &lt;strong&gt;Set-Cookie: name=value;&lt;/strong&gt; и при каждом следующем обращении клиент будет вставлять поле &lt;strong&gt;Cookie: name=value&lt;/strong&gt;. Именно поэтому следует выносить статические файлы на отдельное доменное имя, куда клиент не будет отправлять Cookie. Ведь лишние символы - это лишний трафик. Еще у Cookie имеется путь, к которому они привязаны, имя домена и дата, до которой они действительны. Также бывают "безопасные" Cookie, которые пересылаются серверу только в случае использования https соединения. На использование cookie накладывается ряд ограничений по количеству на домен и по размеру. Поэтому хранить в них что-то серьезное не получится, и обычно довольствуются идентификатором сессии: уникальный набор байт, которые выступают ключем к данным сессии. Сами данные сессии могут храниться в файлах, в базе данных или в memcached. Лет 10 назад еще не задумывались о красоте URL и частенько передавать идентификатор сессии прямо в URL, т.е. примерно так: http://www.example.com/file.php?sid=0D6441FEA4496C2, и все ссылки в этом файле также включали sid=0D6441FEA4496C2. Ужасно некрасиво.&lt;br /&gt;
&lt;br /&gt;
На последок немного расскажу о современных http серверах. Среди используемых наиболее популярны: Apache, Miscrosoft IIS, nginx и lighttpd. Про IIS я не могу ничего сказать, т.к. никогда не сталкивался. Apache долгое время удерживает первое место по популярности. Не смотря на рост nginx и lighttpd, очень часто за ними скрывается все тот же apache. Между apache и nginx или lighttpd существует существенное архитектурное отличие. Первый обслуживает клиентов создавая дочерние потоки (начиная с версии 2) или процессы. Процессы очень удобны если физический сервер используется различными клиентами. В unix каждый процесс обладает своим набором прав и привилегий. И для каждого клиента http сервер запускается с привилегиями этого самого клиента. А значит, клиент не имеет права доступа к файлам другого клиента, который также имеет файлы на этом же сервере. Но к сожалению эта архитектура связана с накладными расходами, поэтому растет популярность альтернативной архитектуры, которой обладают nginx и lighttpd. Они не запускают дочерних потоков или процессов для каждого клиента, а используют асинхронную обработку запросов. Кажется, Алан Кокс (один из основных разработчиков ядра Linux) сказал, что "потоки нужны только тем, кто не умеет программировать конечные автоматы". Операционной системе действительно не очень то удобно переключаться туда-сюда между потоками и процессами, на это тратится драгоценное время. Если в системе сотни процессов/потоков, то ничего страшного, но если их десятки тысяч? Тогда значительно больше ресурсов (CPU и RAM) уйдет на обслуживание этих процессов и потоков, если сервер вообще справится с такой нагрузкой. Асинхронная архитектура позволяет полностью нагрузить процессор только полезной работой. Делается это примерно так: создается один процесс, который принимает запрос от клиента. Или от 10 000 клиентов. Процесс самостоятельно не опрашивает состояние этих клиентов (есть у них данные или нет), а передает список сокетов операционной системе. И как только от клиента придут какие-то данные, система будит процесс и сообщает, какой именно сокет следует читать. Когда http сервер прочитал часть данных и, к примеру, ему нужно прочитать и отдать клиенту большой файл, он выполняет асинхронную фукнцию чтения, запрашивая небольшой кусок из этого файла. Не секрет, что чтение с диска достаточно медленная операция. А у нас в очереди еще есть клиенты, которых можно обслужить, пока выполняется чтение с диска. Поэтому http сервер снова запускает цикл обработки сообщений, продолжая обслуживать клиентов. Как только кусок из файла будет прочитан, http сервер начнет его отправлять. Отправка клиенту, особенно если тот использует медленное соединение, тоже может занять время. Поэтому пока кусок данных уходит, можно успеть обслужить других клиентов. После отправки первого куска файла будет отправлен следующий, за ним другой и т.д. И все это реализуется как конечный автомат (FSM - Finite State Machine). Для реализации подобной архитектуры следует прочитать о epoll на Linux, kqueue на FreeBSD и о портах завершения (IO Completion Ports) на Windows. Но значительно проще воспользоваться библиотекой libev, libevent или Boost.Asio.&lt;br /&gt;
&lt;br /&gt;
Прикладываю пример простенького и совершенно не полноценного HTTP сервера написанного на C++ с использованием Qt: &lt;a href="http://nekipelov.net/blog/example-httpd.tar.gz"&gt;http://nekipelov.net/blog/example-httpd.tar.gz&lt;/a&gt;. Но файлы он отдавать способен и выглядит вроде бы не сложно. Изначально он вообще не был предназначен для раздачи файлов. Также я убрал всю оптимизацию, которая усложняла код. К сожалению из-за этого код немного изуродовался (и нет времени наводить красоту, а тем более делать из него более полноценный сервер), ну и мог где-нибудь мог допустить ошибку, и скорее всего не одну. Если вы наткнетесь на такое, пожалуйста сообщите мне комментарием к статье или лично &lt;a href="mailto:alex@nekipelov.net"&gt;alex@nekipelov.net&lt;/a&gt;. Собирается примерно так: qmake &amp;&amp; make. Мог бы выложить и пример с использованием Asio, но лучше уж взять официальный вот от &lt;a href="http://www.boost.org/doc/libs/1_46_0/doc/html/boost_asio/examples.html"&gt;сюда&lt;/a&gt;. &lt;br /&gt;
&lt;br /&gt;
"Пример" ожидает запросы на 3000 порту, соответственно в браузере следует открывать http://127.0.0.1:3000. Раздает файлы из текущего каталога. Порт можно изменить в файле main.cpp. Процесс работы там простой: ожидаем строку запроса и разбираем ее. Когда принят весь заголовок, вызываем &lt;code&gt;ProcessReqeust::processRequest()&lt;/code&gt; который и обрабатывает http запрос. Я перевел комментарии на русский, кодировка UTF-8. Тем, что все читает на английском моя статья вряд-ли не пригодится :-)&lt;br /&gt;
&lt;br /&gt;
Уф, ну вроде все. Точнее не совсем все, по этой теме можно целую книгу написать, может даже не одну. Но основы я рассказал. Если это не так, сообщите, что я упустил.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8536094954863042356-4646452343696647512?l=blog.nekipelov.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AlexNekipelovBlog/~4/cHujeS2NTvg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/4646452343696647512/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://blog.nekipelov.net/2011/03/http.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/4646452343696647512?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/4646452343696647512?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AlexNekipelovBlog/~3/cHujeS2NTvg/http.html" title="Как написать свой http сервер" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/11644484550750096086</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://1.bp.blogspot.com/-gF40tHGJFbk/TXMfXxe4Z2I/AAAAAAAAADM/Ovx7kQb5p_4/s220/%25D1%258F%2B%25D1%2581%2B%25D1%2581%25D0%25BE%25D0%25B1%25D0%25B0%25D0%25BA%25D0%25BE%25D0%25B9%2B%25D0%25BC%25D0%25B8%25D0%25BD%25D0%25B8.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nekipelov.net/2011/03/http.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0EGQH89fip7ImA9Wx9aEU0.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356.post-6669922181342757778</id><published>2011-03-02T23:43:00.001+03:00</published><updated>2011-03-03T00:33:41.166+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-03T00:33:41.166+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="xpath" /><category scheme="http://www.blogger.com/atom/ns#" term="селекторы" /><category scheme="http://www.blogger.com/atom/ns#" term="C++" /><category scheme="http://www.blogger.com/atom/ns#" term="html" /><title>Парсинг html файлов</title><content type="html">Больше 10 назад, когда еще не было безлимитных тарифов и интернет был дорогим, я был подписан на большое количество всяких рассылок, в основном это были новости. После получения почты интернет отключался (деньги ведь капают) и почта читалась в оффлайн. После я выбирал нужные мне ссылки, складывал в специальный файлик, снова выходил в онлайн, запускал скрипт, который получал все указанные ссылки и складывал по папочкам.&lt;br /&gt;
&lt;br /&gt;
Разумеется читать удобней чистый текст, без назойливой рекламы, без большого количества мусора... поэтому в каждой папочке для соответствующего сайта был набор правил по приведению статьи в пригодный для чтения вид. Конечно же для обработки этих файлов я использовал регулярные выражения и все скрипты были написаны на perl. Было много возьни с этими регулярными выражениями, ругани, особенно, когда структура html файлов менялась.&lt;br /&gt;
&lt;br /&gt;
И к своему стыду, я много лет продолжал эту практику - разбирать html файлы с помощью регулярных выражений. До тех пор, пока не пришлось повозиться с jQuery. Возможно кто-то еще продолжает так делать, поэтому заметка для них. Для разбора html файлов значительно быстрее и удобнее применять XPath или CSS селекторы. Не говоря уже о том, что зачастую структура html файла просто не поддается нормальному разбору с помощью регулярных выражений и такой то матери.&lt;br /&gt;
&lt;br /&gt;
К примеру выбор всех изображений, являющихся ссылками с помощью CSS селекторов: "a &gt; img", с помощью XPath - "//a/img".&lt;br /&gt;
&lt;br /&gt;
При этом нормальные библиотеки, к примеру libxml позволяют работать и с невалидным html файлом. Обертки над libxml есть для большинства языков, например nokogiri для ruby или lxml для python.&lt;br /&gt;
&lt;br /&gt;
Замечу, что отличие CSS селекторов от XPath в большей краткости первого способа, но большей производительности второго.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8536094954863042356-6669922181342757778?l=blog.nekipelov.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AlexNekipelovBlog/~4/ucFlmEF8HFs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/6669922181342757778/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://blog.nekipelov.net/2011/03/html.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/6669922181342757778?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/6669922181342757778?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AlexNekipelovBlog/~3/ucFlmEF8HFs/html.html" title="Парсинг html файлов" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/11644484550750096086</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://1.bp.blogspot.com/-gF40tHGJFbk/TXMfXxe4Z2I/AAAAAAAAADM/Ovx7kQb5p_4/s220/%25D1%258F%2B%25D1%2581%2B%25D1%2581%25D0%25BE%25D0%25B1%25D0%25B0%25D0%25BA%25D0%25BE%25D0%25B9%2B%25D0%25BC%25D0%25B8%25D0%25BD%25D0%25B8.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nekipelov.net/2011/03/html.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkYCQXw5eip7ImA9Wx9bGE8.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356.post-5001965640839990906</id><published>2011-02-27T14:18:00.001+03:00</published><updated>2011-02-27T19:29:20.222+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-27T19:29:20.222+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="оптимизация" /><category scheme="http://www.blogger.com/atom/ns#" term="stl" /><category scheme="http://www.blogger.com/atom/ns#" term="C++" /><title>Альтернатива ассоциативным контейнерам в C++</title><content type="html">Сегодня наткнулся на статейку &lt;a href="http://habrahabr.ru/blogs/cpp/114518/"&gt;http://habrahabr.ru/blogs/cpp/114518/&lt;/a&gt;. Совет рассмотреть альтернативы ассоциативным контейнерам конечно хороший. Вот только тестирование производительности совершенно неправильное.&lt;br /&gt;
&lt;br /&gt;
Судя по результатам, в &lt;code&gt;vector&lt;/code&gt; вставка осуществлялась без предварительного вызова reserve. Следовательно много времени ушло на перевыделение памяти. Вызывать &lt;code&gt;reserve&lt;/code&gt; следует всегда, хотя-бы для ориентировочного количества элементов.&lt;br /&gt;
&lt;br /&gt;
А вставка в &lt;code&gt;map&lt;/code&gt; выполнялась с помощью перегруженного &lt;code&gt;operator[]&lt;/code&gt;. Это очень плохо потому, что каждый вызов &lt;code&gt;operator[]&lt;/code&gt; сначала выполняет поиск и только потом вставку. Поэтому вставлять большое количество элементов следует с помощью метода &lt;code&gt;insert&lt;/code&gt;. Разумеется в этом случае вставляемые данные должны быть предварительно отсортированы.&lt;br /&gt;
&lt;br /&gt;
От себя дам другой совет: используйте контейнеры ориентируясь на их слабые и сильные стороны. Например вставка без предварительного выделения памяти очень быстро выполняется в &lt;code&gt;deque&lt;/code&gt;. С предварительным выделением и в &lt;code&gt;vector&lt;/code&gt;. А если требуется вставить множество элементов в ассоциативный контейнер, в случаях, когда последовательность этих элементов идет в случайном порядке, следует сначала вставить их в &lt;code&gt;vector&lt;/code&gt; или &lt;code&gt;deque&lt;/code&gt;, отсортировать и только потом вставлять в ассоциативный контейнер с помощью метода &lt;code&gt;insert&lt;/code&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8536094954863042356-5001965640839990906?l=blog.nekipelov.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AlexNekipelovBlog/~4/ZXK0GxciqLs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/5001965640839990906/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://blog.nekipelov.net/2011/02/c.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/5001965640839990906?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/5001965640839990906?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AlexNekipelovBlog/~3/ZXK0GxciqLs/c.html" title="Альтернатива ассоциативным контейнерам в C++" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/11644484550750096086</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://1.bp.blogspot.com/-gF40tHGJFbk/TXMfXxe4Z2I/AAAAAAAAADM/Ovx7kQb5p_4/s220/%25D1%258F%2B%25D1%2581%2B%25D1%2581%25D0%25BE%25D0%25B1%25D0%25B0%25D0%25BA%25D0%25BE%25D0%25B9%2B%25D0%25BC%25D0%25B8%25D0%25BD%25D0%25B8.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nekipelov.net/2011/02/c.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUQBQnc4cSp7ImA9Wx9bEEU.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356.post-7356576722158276421</id><published>2011-02-19T06:47:00.002+03:00</published><updated>2011-02-19T06:49:13.939+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-19T06:49:13.939+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="std::locale" /><category scheme="http://www.blogger.com/atom/ns#" term="g++" /><category scheme="http://www.blogger.com/atom/ns#" term="gcc" /><category scheme="http://www.blogger.com/atom/ns#" term="locale" /><category scheme="http://www.blogger.com/atom/ns#" term="C++" /><title>std::locale в gcc</title><content type="html">Завершил доработку для приложения и пошел обновлять его на сервере. Но там оно не заработало, выдавая исключение &lt;strong&gt;locale::facet::_S_create_c_locale name not valid&lt;/strong&gt;. При том, что локаль ru_RU.UTF-8 вообще-то имеется в системе и все должно быть нормально.&lt;br /&gt;
&lt;br /&gt;
А как раз перед этим я собирал новый gcc (мне понадобились кое-какие фичи из C++0x). Быстренько глянул в google, ответа не нашел. Пришлось лезть в исходники libstdc++, где я обнаружил два различных места установки локали, причем в одном из них принимается только локаль "C" и ничего больше. Последнее называлось generic, а мне нужна была фукнциональность из gnu.&lt;br /&gt;
&lt;br /&gt;
Полез в скрипты и логи configure, и выяснил, что оно пытается установить локаль de_DE и если этого не получилось, выбирает generic, т.е. просто не использует локали! Ну а я не люблю, когда в системе что-то лишнее. Естественно, что я не стал ставить de_DE. Пришлось уж ее поставить  (&lt;code&gt;dpkg-reconfigure locales &amp;&amp; locale-gen&lt;/code&gt;) и только после этого все собралось как надо.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8536094954863042356-7356576722158276421?l=blog.nekipelov.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AlexNekipelovBlog/~4/4UMfmRal4fs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/7356576722158276421/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://blog.nekipelov.net/2011/02/stdlocale-gcc.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/7356576722158276421?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/7356576722158276421?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AlexNekipelovBlog/~3/4UMfmRal4fs/stdlocale-gcc.html" title="std::locale в gcc" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/11644484550750096086</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://1.bp.blogspot.com/-gF40tHGJFbk/TXMfXxe4Z2I/AAAAAAAAADM/Ovx7kQb5p_4/s220/%25D1%258F%2B%25D1%2581%2B%25D1%2581%25D0%25BE%25D0%25B1%25D0%25B0%25D0%25BA%25D0%25BE%25D0%25B9%2B%25D0%25BC%25D0%25B8%25D0%25BD%25D0%25B8.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nekipelov.net/2011/02/stdlocale-gcc.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEMMSX49eCp7ImA9WxBWE08.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356.post-264179567960377736</id><published>2010-02-04T14:01:00.002+03:00</published><updated>2010-02-05T02:34:48.060+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-05T02:34:48.060+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="оптимизация" /><category scheme="http://www.blogger.com/atom/ns#" term="базы данных" /><title>Враг производительности - фрагментация</title><content type="html">Сегодня разбирался с неожиданно возникшей проблемой. Одна из функций системы стала вести себя неадекватно. Эта "функция" инициировала большое количество операций чтения с диска. Проблема была в том, что через какое-то время скорость чтения с диска падала до 2-х мегабайт в секунду. Профилировал, отлаживал... но понять, откуда берется разница не смог. &lt;br /&gt;&lt;br /&gt;Решил отвлечься, и тут меня осенило: да это же фрагментация! Из-за того, что файлы базы данных были сильно фрагментированы, скорость чтения упала в 20 раз. Аж стыдно признаваться, что я сразу это не понял. Но у меня есть оправдание: к моменту разбирательств мой рабочий день длился уже 14 часов.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8536094954863042356-264179567960377736?l=blog.nekipelov.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AlexNekipelovBlog/~4/tmRqt5e6NHQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/264179567960377736/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://blog.nekipelov.net/2010/02/blog-post.html#comment-form" title="Комментарии: 1" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/264179567960377736?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/264179567960377736?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AlexNekipelovBlog/~3/tmRqt5e6NHQ/blog-post.html" title="Враг производительности - фрагментация" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/11644484550750096086</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://1.bp.blogspot.com/-gF40tHGJFbk/TXMfXxe4Z2I/AAAAAAAAADM/Ovx7kQb5p_4/s220/%25D1%258F%2B%25D1%2581%2B%25D1%2581%25D0%25BE%25D0%25B1%25D0%25B0%25D0%25BA%25D0%25BE%25D0%25B9%2B%25D0%25BC%25D0%25B8%25D0%25BD%25D0%25B8.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://blog.nekipelov.net/2010/02/blog-post.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkIAQXk8eSp7ImA9WxJbFEQ.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356.post-3804491138936663668</id><published>2009-07-17T07:22:00.009+04:00</published><updated>2009-07-25T08:02:20.771+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-07-25T08:02:20.771+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="отладка" /><category scheme="http://www.blogger.com/atom/ns#" term="C++" /><title>Выявление места исключения по адресу инструкции</title><content type="html">Проблемы отладки и поиска ошибок преследуют нас, программистов, постоянно. Иногда может получится так, что у нас нет pdb файлов с отладочной информацией, или они потерялись, или они есть, но по какой-то причине не получается создать файл дампа... в общем причин может быть много, но из данных у нас только адрес инструкции и имя модуля, в котором произошло исключение. Не все знают, что в этом случае найти точное место исключения достаточно просто.&lt;br /&gt;&lt;br /&gt;Разберем пример с ошибкой:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class Foo {&lt;br /&gt; public:&lt;br /&gt;  Foo() : i(0) {}&lt;br /&gt;&lt;br /&gt;  int bar() const {&lt;br /&gt;    return i;&lt;br /&gt;  } &lt;br /&gt; private:&lt;br /&gt;  int i;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;int main(int, char **)&lt;br /&gt;{&lt;br /&gt; Foo *foo = 0;&lt;br /&gt; foo-&gt;bar();&lt;br /&gt; &lt;br /&gt; return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Конечно в данном случае ошибка видна явно. Но допустим, что мы не видим, где и как инициализируется указатель на &lt;strong&gt;foo&lt;/strong&gt;. При запуске получим примерно такое вот сообщение:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_irbFwfqZ_L8/Sl_zqv5epCI/AAAAAAAAABk/8kSG4eukmqE/s1600-h/scr5.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 86px;" src="http://2.bp.blogspot.com/_irbFwfqZ_L8/Sl_zqv5epCI/AAAAAAAAABk/8kSG4eukmqE/s400/scr5.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5359269997331784738" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Теперь нам нужен map файл для модуля, в котором произошла ошибка (аргумент /Fm компилятора Visual C++). Вот кусок из map файла для данной программы:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  Address         Publics by Value              Rva+Base     Lib:Object&lt;br /&gt;&lt;br /&gt; 0001:00000000       _main                      00401000 f   crush.obj&lt;br /&gt; 0001:00000020       ?bar@Foo@@QBEHXZ           00401020 f i crush.obj&lt;br /&gt; 0001:00000030       _mainCRTStartup            00401030 f   LIBC:crt0.obj&lt;br /&gt; 0001:0000010f       __amsg_exit                0040110f f   LIBC:crt0.obj&lt;br /&gt; 0001:00000158       __cinit                    00401158 f   LIBC:crt0dat.obj&lt;br /&gt; 0001:00000185       _exit                      00401185 f   LIBC:crt0dat.obj&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Нас интересует колонка Rva+Base. Это адреса фукнций, по которым они расположены в памяти. А в сообщении об ошибке мы имеем адрес инструкции. В нашем случае он &lt;strong&gt;0x0040102a&lt;/strong&gt;. Найдя в таблице ближайший адрес меньше нашего, мы узнаем фукцнию и объектный файл, ответственные за это безобразие. Нам подходит адрес 00401020, следовательно это функция ?bar@Foo@@QBEHXZ в объектном файле crush.obj. Разумеется имя фукцнии декорировано. Разница между адресом фукнции и адресом исключение - будет локальное смешение внутри фукнции. Чтобы понять, что находится по смещению 0x0a  (0x0040102a-00401020) нужен файл листинга (аргумент /FAsc компилятора Visual C++, результат в виде файла с расширением cod). Этот файл содержит C++ код, ассемблрные команды, в которые он был преобразован и машинный код.&lt;br /&gt;&lt;br /&gt;Вот как выглядит результат для нашего метода Foo::bar()&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;; COMDAT ?bar@Foo@@QBEHXZ&lt;br /&gt;_TEXT SEGMENT&lt;br /&gt;_this$ = -4&lt;br /&gt;?bar@Foo@@QBEHXZ PROC NEAR    ; Foo::bar, COMDAT&lt;br /&gt;&lt;br /&gt;; 5    :   int bar() const {&lt;br /&gt;&lt;br /&gt;  00000 55   push  ebp&lt;br /&gt;  00001 8b ec   mov  ebp, esp&lt;br /&gt;  00003 51   push  ecx&lt;br /&gt;  00004 89 4d fc  mov  DWORD PTR _this$[ebp], ecx&lt;br /&gt;&lt;br /&gt;; 6    :     return i;&lt;br /&gt;&lt;br /&gt;  00007 8b 45 fc  mov  eax, DWORD PTR _this$[ebp]&lt;br /&gt;  0000a 8b 00   mov  eax, DWORD PTR [eax]&lt;br /&gt;&lt;br /&gt;; 7    :   } &lt;br /&gt;&lt;br /&gt;  0000c 8b e5   mov  esp, ebp&lt;br /&gt;  0000e 5d   pop  ebp&lt;br /&gt;  0000f c3   ret  0&lt;br /&gt;?bar@Foo@@QBEHXZ ENDP     ; Foo::bar&lt;br /&gt;_TEXT ENDS&lt;br /&gt;END&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Чтобы не осталось вопросов, разберем детальнее. Код начинается со строки:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;; 5    :   int bar() const {&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;; 5&lt;/strong&gt; - это номер строки в исходном файле. Дальше идет текст из исходного файла.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  00000 55   push  ebp&lt;br /&gt;  00001 8b ec   mov  ebp, esp&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Первая колонка, содержащая 00000 и 00001, это и есть нужные нам адреса инструкций. Следующие цифры представляют из себя так называемый опкод (от англ. operation code), это машинная инструкция, которая отправляется процессору. Из таких инструкций и состоит исполняемый код. Ну а после этого идет ассемблерная команда. &lt;br /&gt;&lt;br /&gt;По искомому адресу 0x0a находится следующий код:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;; 6    :     return i;&lt;br /&gt;&lt;br /&gt;  00007 8b 45 fc  mov  eax, DWORD PTR _this$[ebp]&lt;br /&gt;  0000a 8b 00   mov  eax, DWORD PTR [eax]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Тут возвращается значение члена класса. Первой строкой вычисляется смещение, по которому расположена переменная i, второй происходит чтение данных, расположенных по этому адресу. Мы нашли место ошибки, и теперь видим, какую ошибку нужно искать.&lt;br /&gt;&lt;br /&gt;Для того, чтобы этот метод работал, требуется неизменность исходников. Как только в исходных текстах будет изменена хотя-бы одна строка, все адреса потеряют смысл. Поэтому у вас два варианта: генерировать все необходимые файлы сразу при компиляции, или сохранять исходные тексты каждого отправляемого приложения.&lt;br /&gt;&lt;br /&gt;Я описал работу только с компилятором &lt;strong&gt;Visual C++&lt;/strong&gt;, но описанная методика подходит и для других популярных компиляторов для ОС Windows. В Linux/unix, как правило, к таким ухищрениям прибегать не приходится.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8536094954863042356-3804491138936663668?l=blog.nekipelov.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AlexNekipelovBlog/~4/6YW9aDIrXmc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/3804491138936663668/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://blog.nekipelov.net/2009/07/blog-post.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/3804491138936663668?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/3804491138936663668?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AlexNekipelovBlog/~3/6YW9aDIrXmc/blog-post.html" title="Выявление места исключения по адресу инструкции" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/11644484550750096086</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://1.bp.blogspot.com/-gF40tHGJFbk/TXMfXxe4Z2I/AAAAAAAAADM/Ovx7kQb5p_4/s220/%25D1%258F%2B%25D1%2581%2B%25D1%2581%25D0%25BE%25D0%25B1%25D0%25B0%25D0%25BA%25D0%25BE%25D0%25B9%2B%25D0%25BC%25D0%25B8%25D0%25BD%25D0%25B8.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_irbFwfqZ_L8/Sl_zqv5epCI/AAAAAAAAABk/8kSG4eukmqE/s72-c/scr5.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.nekipelov.net/2009/07/blog-post.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0cAQ3YycCp7ImA9WxJTE0g.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356.post-2425947546740166787</id><published>2009-04-22T03:46:00.005+04:00</published><updated>2009-04-22T04:10:42.898+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-22T04:10:42.898+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="базы данных" /><category scheme="http://www.blogger.com/atom/ns#" term="InnoDB" /><title>Еще одна маленькая БД: Embedded InnoDB</title><content type="html">Сегодня &lt;a href="http://www.opennet.ru"&gt;OpenNet&lt;/a&gt; обрадовал новыми новостями. Наконец-то вышел релиз GCC 4.4.0, новая версия MySQL... и очередная встраиваемая БД. Вот текст новости:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Компания Oracle выпустила под лицензией GPLv2 вариант транзакционного хранилища данных Embedded InnoDB, предназначенного для использования независимо от MySQL, путем прямого встраивания движка в пользовательское приложение.&lt;br /&gt;&lt;br /&gt;Доступ к данным производится через низкоуровневый набор функций, в корне отличающийся по синтаксису от SQL и больше напоминающий ISAM-подобный API. При этом поддерживаются операции работы с курсором, управление транзакциями и возможность использования индексов. Размер присоединяемой к приложению библиотеки составляет 838 Кб, поддерживаются языки C и C++. С точки зрения поддержки одновременного доступа к базе, допускается использование библиотеки в многопоточных программах и жестко конкурирующих процессах. Подключение базы организуется примерно тем же способом, что и BerkeleyDB.&lt;br /&gt;&lt;br /&gt;Некоторые из заявленных возможностей Embedded InnoDB:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;    &lt;li&gt;Встроенные средства для восстановления целостности базы после краха;&lt;br /&gt;    &lt;li&gt;Возможность хранения данных в сжатом виде;&lt;br /&gt;    &lt;li&gt;Высокая производительность и масштабируемость;&lt;br /&gt;    &lt;li&gt;Мультиверсионный механизм обработки одновременных запросов с поддержкой блокировки на уровне строк;&lt;br /&gt;    &lt;li&gt;Автоматическое выявление взаимных блокировок (deadlock);&lt;br /&gt;    &lt;li&gt;Возможности кластеризации и подключения вторичных B-tree индексов;&lt;br /&gt;    &lt;li&gt;Автоматическая буферизация добавляемых в базу данных. &lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Источник: http://www.opennet.ru/opennews/art.shtml?num=21377&lt;br /&gt;&lt;br /&gt;Совсем недавно я писал о Berkeley DB (&lt;a href="http://alex-nekipelov.blogspot.com/2009/03/berkeley-db.html"&gt;http://alex-nekipelov.blogspot.com/2009/03/berkeley-db.html&lt;/a&gt;.) Похоже, что в полку прибыло. На фоне засилья больших и медленных RDBMS, это очень радует.&lt;br /&gt;&lt;br /&gt;Совпадение, что &lt;strong&gt;InnoDB&lt;/strong&gt;, как и &lt;strong&gt;Berkeley DB&lt;/strong&gt;, используется в качестве движка в MySQL. Учитывая последнюю новость о покупке Sun компанией Oracle (&lt;a href="http://www.sun.com/third-party/global/oracle/index.jsp"&gt;http://www.sun.com/third-party/global/oracle/index.jsp&lt;/a&gt;), наверное стоит ждать еще и &lt;strong&gt;Embedded MyIASM&lt;/strong&gt;? :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8536094954863042356-2425947546740166787?l=blog.nekipelov.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AlexNekipelovBlog/~4/bpZrBisklVg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/2425947546740166787/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://blog.nekipelov.net/2009/04/embedded-innodb.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/2425947546740166787?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/2425947546740166787?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AlexNekipelovBlog/~3/bpZrBisklVg/embedded-innodb.html" title="Еще одна маленькая БД: Embedded InnoDB" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/11644484550750096086</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://1.bp.blogspot.com/-gF40tHGJFbk/TXMfXxe4Z2I/AAAAAAAAADM/Ovx7kQb5p_4/s220/%25D1%258F%2B%25D1%2581%2B%25D1%2581%25D0%25BE%25D0%25B1%25D0%25B0%25D0%25BA%25D0%25BE%25D0%25B9%2B%25D0%25BC%25D0%25B8%25D0%25BD%25D0%25B8.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nekipelov.net/2009/04/embedded-innodb.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0ADR388fyp7ImA9WxVbEE4.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356.post-7540482119057011100</id><published>2009-03-26T03:45:00.005+03:00</published><updated>2009-03-26T05:49:36.177+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-26T05:49:36.177+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="gcc" /><category scheme="http://www.blogger.com/atom/ns#" term="параллельные вычисления" /><category scheme="http://www.blogger.com/atom/ns#" term="C++" /><title>Параллельные вычисления</title><content type="html">Все знают, что наступает эпоха многоядерности в сегменте персональных компьютеров. А это значит, что для того, чтобы заставить программы работать быстрее, необходимо писать код, загружающий все доступные процессоры. И, наверное, в перспективе, это будет основной способ повышения быстродействия. По крайней мере я на это надеюсь.&lt;br /&gt;&lt;br /&gt;К сожалению для программистов это означает очередные сложности. Одно дело распараллелить большую задачу по обработке данных, которую можно разбить на независимые блоки. Или сервер, обслуживающий множество запросов... И совсем другое, распраллеливать каждодневные операции. Язык C++, в отличии от функциональных языков программирования, мало предназначен для распараллеливания. Однако в этом направлении намечаются улучшения. Начиная с версии 4.2 в компилятор GCC включена поддержка OpenMP. Также она имеется и в других современных компиляторах (от Microsoft, Sun, Intel). В грядущей версии GCC 4.4 обещают автоматическое распараллеливание циклов. Эта новость меня очень обрадовала. Это означает, что всю кучу уже написанного в Linux кода, который вряд-ли кто-либо соберется переписывать с учетом многоядерности, можно будет чуть-чуть ускорить.&lt;br /&gt;&lt;br /&gt;И еще, меня обрадовал случайно обнаруженный каталог /usr/include/c++/4.3/parallel. Я только недавно установил последнюю версию gcc и даже не ожидал увидеть там такое, почему-то пропустил release notes (слишком много дел, даже не успеваю следить за нужными новостями). Там содержатся основные алгоритмы STL, использующие многопоточность на основе OpenMP: &lt;a href="http://gcc.gnu.org/onlinedocs/libstdc++/manual/parallel_mode.html"&gt;http://gcc.gnu.org/onlinedocs/libstdc++/manual/parallel_mode.html&lt;/a&gt;. Может быть скоро я перестану поглядывать на TBB (&lt;a href="http://www.threadingbuildingblocks.org/"&gt;http://www.threadingbuildingblocks.org/&lt;/a&gt;).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8536094954863042356-7540482119057011100?l=blog.nekipelov.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AlexNekipelovBlog/~4/Zm7qdzW7eNk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/7540482119057011100/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://blog.nekipelov.net/2009/03/blog-post.html#comment-form" title="Комментарии: 1" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/7540482119057011100?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/7540482119057011100?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AlexNekipelovBlog/~3/Zm7qdzW7eNk/blog-post.html" title="Параллельные вычисления" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/11644484550750096086</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://1.bp.blogspot.com/-gF40tHGJFbk/TXMfXxe4Z2I/AAAAAAAAADM/Ovx7kQb5p_4/s220/%25D1%258F%2B%25D1%2581%2B%25D1%2581%25D0%25BE%25D0%25B1%25D0%25B0%25D0%25BA%25D0%25BE%25D0%25B9%2B%25D0%25BC%25D0%25B8%25D0%25BD%25D0%25B8.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://blog.nekipelov.net/2009/03/blog-post.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A04NRXc9eCp7ImA9WxVbEE8.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356.post-6022550530783642989</id><published>2009-03-26T02:28:00.007+03:00</published><updated>2009-03-26T04:13:14.960+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-26T04:13:14.960+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="базы данных" /><category scheme="http://www.blogger.com/atom/ns#" term="bdb" /><title>Заметка о маленькой БД, с большими возможностями: Berkeley DB</title><content type="html">Недавно передо мной встала задача получить быстрый доступ по 4-х байтовому ключу к данным, размер которых 8 байт. Всегда такая задача решается элементарно через std::map, или что-нибудь подобное hash_map... но на этот раз количество элементов превышает 150 млн. При этом нужно уместиться в адресное пространство на Windows (2 гагабайта), и очень хотелось бы оставить еще немного памяти для работы. Потенциально размер ключа может быть увеличен до 8-и байт, а количество элементов растет с каждым днем. Разумеется в оперативной памяти такой объем не уместить.&lt;br /&gt;&lt;br /&gt;Обдумывая решение для сложившейся ситуации вспомнил про такую хорошую штуку, как dbm. Задачи, подобные моей (т.е. хранение большого количества данных с доступом по ключу) возникают у многих, если не у всех. И когда-то давным давно, когда программы еще были маленькими, а компьютеры большими... Кен Томпсон (да-да, тот самый, создатель unix и языка C) придумал и реализовал стандартный интерфейс Database Manager для доступа к данным по ключу. Подробнее о dbm написано тут: &lt;a href="http://en.wikipedia.org/wiki/dbm"&gt;http://en.wikipedia.org/wiki/dbm&lt;/a&gt;. Программисты, переписывающие проприетарный unix для проектов BSD и GNU реализовали аналоги: Berkeley DB (далее BDB) и GNU Dbm. Конечно же есть и множество других клонов... но они не относятся к делу. Так вот, GNU Dbm  как то так и остался на том же уровне, а вот создатели BDB развивали и совершенствовали свое детище. Кстати, интересный факт: одним из создателей является программист - женщина :-)&lt;br /&gt;&lt;br /&gt;С тех пор прошло много времени, проект BDB немного подрос... сейчас скомпилированная версия 4.26 занимает 1 мегабайт. По нынешним меркам, совсем крошечная программа. Но нужно смотреть на ее возможности:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Примерно 200 000 000 (200 млн) пользователей этой БД, по данным компании Oracle.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Возможность обслуживать одновременно тысячи процессов или потоков.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Поддержка баз данных объемом до 256 ТБ.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Кроссплатформенность (большинство unix, Windows, в том числе и мобильная CE, некоторые Real-Time OS).&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Наличие интерфейсов для множества языков (C, C++, java, ruby, perl, python, tcl...)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Полноценная поддержка ACID транзакций.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;4 режима организации данных (B-Tree, Hash, Queue, RecNo).&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Высокая скорость (примерно 1 млн операций чтения или 0,5 млн&lt;br /&gt;операций записи в секунду на обычных десктопных компьютерах).&lt;br /&gt;Разумеется это в случае не использования транзакций.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Лицензия на любой вкус: свободная или комерческая&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Ну как, впечатляет? А ведь это еще не все...&lt;br /&gt;&lt;br /&gt;Разработкой BDB занималась компания Sleepycat Software, которая была приобретена компанией Oracle в 2006 году. Официальный сайт BDB тут: &lt;a href="http://www.oracle.com/technology/products/berkeley-db/index.html"&gt;http://www.oracle.com/technology/products/berkeley-db/index.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;В следующий раз, обдумывая вопрос, какую из встраиваемых баз данных применить, вспомните про малышку BDB. Конечно это не реляционная БД, отсутствует удобный язык запросов, к которому все привыкли... но именно поэтому ни одна реляционная БД не сможет сравниться в скорости с BDB.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8536094954863042356-6022550530783642989?l=blog.nekipelov.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AlexNekipelovBlog/~4/G-tziyXx-w8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/6022550530783642989/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://blog.nekipelov.net/2009/03/berkeley-db.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/6022550530783642989?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/6022550530783642989?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AlexNekipelovBlog/~3/G-tziyXx-w8/berkeley-db.html" title="Заметка о маленькой БД, с большими возможностями: Berkeley DB" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/11644484550750096086</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://1.bp.blogspot.com/-gF40tHGJFbk/TXMfXxe4Z2I/AAAAAAAAADM/Ovx7kQb5p_4/s220/%25D1%258F%2B%25D1%2581%2B%25D1%2581%25D0%25BE%25D0%25B1%25D0%25B0%25D0%25BA%25D0%25BE%25D0%25B9%2B%25D0%25BC%25D0%25B8%25D0%25BD%25D0%25B8.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nekipelov.net/2009/03/berkeley-db.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkEDQHo_eSp7ImA9WxdRGUo.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356.post-8750247904622416348</id><published>2008-06-09T02:52:00.000+04:00</published><updated>2008-06-09T04:17:51.441+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-09T04:17:51.441+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="программы" /><title>программы, без которых я не могу обойтись</title><content type="html">Недавно, во многих программистских блогах, прошла акция (точнее, пошла вторая волна) "программы, которые я использую каждый день", другой вариант: "программы, без которых я не могу обойтись". Я подумал и решил вложить свои 5 копеек:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;&lt;a href="http://www.vim.org"&gt;VIM&lt;/a&gt; в качестве текстового редактора. Он по праву носит имя одного из самых мощных универсальных редакторов, по возможностям его обгонит разве что emacs. Поддержка огромного количества языков, возможность полной настройки, большое количество плагинов, отсутствие привязки к GUI и много всего другого.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;&lt;a href="http://www.mozilla.com/firefox/"&gt;Firefox&lt;/a&gt; в качестве браузера. Когда-то давно мне очень нравится браузер Netscape 4. Главное, что он был быстрым и удобным. Потом появилась Mozilla и Netscape 6, чуть позже Firefox и большое количество других, использующих движок Gecko. Но у всех была одна проблема: очень медленная скорость работы. Но мир www очень активно развивался, поэтому постепенно мне пришлось отказаться от использования Netscape в пользу Opera. Но, к сожалению, по некоторым причинам, в прошлом году я решил отказаться от Opera в пользу Firefox. В качестве бонуса я получил полноценное и удобное средство разработки и отладки web разработок с плагинами Firebug и Web Developer.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;&lt;a href="http://www.perl.org/"&gt;perl&lt;/a&gt; в качестве универсального помощника. Иногда я использую этот язык для web приложений, но чаще всего по его прямому назначению: обработка и извлечение данных. Это очень удобный инструмент, когда нужно обработать десятки (сотни, тысячи и т.д.) файлов. Посчитать что-либо и вывести результат, просто заменить какие-либо выражения, и т.д. &lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Midnight Commander в Linux или Far Manager в Windows. Уж как-то исторически сложилось, что я привык к файловым менеджерам в стиле Norton Commander и не могу комфортно себя чувствовать в пустой консоли или чем-нибудь в стиле проводника. Возможно это потому, что в домашнем каталоге уже меня всегда бардак, приходится туда-сюда перетаскивать, разбирать, лазить по архивам... :-)&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;&lt;a href="http://gcc.gnu.org/"&gt;GNU GCC&lt;/a&gt; - в качестве компилятора C и C++. C++ является для меня основным языком разработки. Иногда использую icc или msvc, но g++ является эталонным компилятором.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;&lt;a href="http://www.mplayerhq.hu/"&gt;MPlayer&lt;/a&gt; для проигрывания как аудио, так и видео. Это самый быстрый и удобный проигрыватель. У него нет GUI (при желании frond-end`ов конечно предостаточно), большой набор кодеков, управление с клавиатуры.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;VirtualBox и VMWare для создания виртуального окружения.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;MySQL и PostgreSQL в качестве серверов баз данных. Мне нравятся обе программы, а выбор происходит в зависимости от положения звезд на небе. Надеюсь, мое руководство не доберется до этого блога и не спросит, почему это я не выбираю БД, разработкой которой я занимаюсь :-)&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;На этом список конечно не заканчивается, но самые основные программы упомянуты. Я ничего не написал про среду разработки, которая является, наверное, самой важной программой для программиста. К сожалению, у меня нет полной определенности в этом вопросе. Когда определюсь, напишу :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8536094954863042356-8750247904622416348?l=blog.nekipelov.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AlexNekipelovBlog/~4/-aIYJVML6Lk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/8750247904622416348/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://blog.nekipelov.net/2008/06/blog-post.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/8750247904622416348?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/8750247904622416348?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AlexNekipelovBlog/~3/-aIYJVML6Lk/blog-post.html" title="программы, без которых я не могу обойтись" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/11644484550750096086</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://1.bp.blogspot.com/-gF40tHGJFbk/TXMfXxe4Z2I/AAAAAAAAADM/Ovx7kQb5p_4/s220/%25D1%258F%2B%25D1%2581%2B%25D1%2581%25D0%25BE%25D0%25B1%25D0%25B0%25D0%25BA%25D0%25BE%25D0%25B9%2B%25D0%25BC%25D0%25B8%25D0%25BD%25D0%25B8.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nekipelov.net/2008/06/blog-post.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0cFSX49eip7ImA9WxZbGUU.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356.post-8333413299723965581</id><published>2008-04-23T13:08:00.000+04:00</published><updated>2008-04-24T02:16:58.062+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-04-24T02:16:58.062+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="венгерская нотация" /><category scheme="http://www.blogger.com/atom/ns#" term="MFC" /><category scheme="http://www.blogger.com/atom/ns#" term="C++" /><title>Венгерская нотация - это зло</title><content type="html">Сегодня продолжал портирование ядра нашей ERP системы на Qt. На очереди была библиотека графического интерфейса. Из-за отсутствия многих стандартных GUI компонентов нагородили своих, усиленно используя библиотеку MFC от Microsoft. Я не являюсь ненавистником продукции Miscrosoft, но поделка под названием &lt;strong&gt;Microsoft Foundation Class Library&lt;/strong&gt; пожалуй одна из ужаснейших, что я встречал. Особенно ужасает дизайн классов и использование &lt;strong&gt;венгерской нотации&lt;/strong&gt;. Разбираясь в дебрях этих совершенно не понятных и неадекватных имен типов и переменных у меня вырабатывается ужасное отвращение к ней. Помнится, она была принята во времена, "когда компьютеры были большими, а программы маленькими". В те времена не было такой простой навигации по исходным текста. Но те времена прошли давным давно. Сейчас можно нажать элементарную комбинацию клавиш и увидеть тип переменной.&lt;br /&gt;&lt;br /&gt;Особенно неприятно становится, когда ее используют неправильно. А она по своей природе способствует неправильному применению.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;    &lt;li&gt;Программисты забывают дать осмысленное имя переменной. И приходится лицезреть что-нибудь вроде &lt;nobr&gt;&lt;strong&gt;LPCWSTR lpcwstrStr&lt;/strong&gt;&lt;/nobr&gt;.&lt;/li&gt;&lt;br /&gt;    &lt;li&gt;Изменяя тип переменной забывают изменить префикс. В таких случаях ее применение вообще теряет какой-либо смысл, кроме замусоривания кода случайными символами.&lt;/li&gt;&lt;br /&gt;    &lt;li&gt;Изначально она использовалась для языка &lt;strong&gt;C&lt;/strong&gt;, где небольшое количество типов данных. В &lt;strong&gt;C++&lt;/strong&gt; типов стало гораздо больше, т.к. само программирование стало ориентированным на объекты. Придумать для каждого типа свой префикс уже сложно, если только они не будут такой же длинной, как имена классов.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;И что самое неприятно, я не вижу ни одного плюса в ее использовании, кроме отпадания необходимости придумывать осмысленное имя. Однако зная, что исходный код чаще читается, чем пишется, это нельзя назвать плюсом.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8536094954863042356-8333413299723965581?l=blog.nekipelov.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AlexNekipelovBlog/~4/Tk8NnsoTcv0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/8333413299723965581/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://blog.nekipelov.net/2008/04/blog-post_23.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/8333413299723965581?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/8333413299723965581?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AlexNekipelovBlog/~3/Tk8NnsoTcv0/blog-post_23.html" title="Венгерская нотация - это зло" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/11644484550750096086</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://1.bp.blogspot.com/-gF40tHGJFbk/TXMfXxe4Z2I/AAAAAAAAADM/Ovx7kQb5p_4/s220/%25D1%258F%2B%25D1%2581%2B%25D1%2581%25D0%25BE%25D0%25B1%25D0%25B0%25D0%25BA%25D0%25BE%25D0%25B9%2B%25D0%25BC%25D0%25B8%25D0%25BD%25D0%25B8.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nekipelov.net/2008/04/blog-post_23.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak8AQno8cSp7ImA9WxJTE0g.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356.post-2417223838766142744</id><published>2008-04-04T00:52:00.001+04:00</published><updated>2009-04-22T04:07:23.479+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-22T04:07:23.479+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="размышления" /><category scheme="http://www.blogger.com/atom/ns#" term="программы" /><title>Размышления о современном ПО</title><content type="html">Я тесно общаюсь с компьютерными программами еще со времен DOS`а. Как говорят, &lt;q&gt;Когда компьютеры были большими, а программы маленькими&lt;/q&gt;. И ведь так и было. Программа должна была помещаться на дискету размером 5,25" и объемом 360 кб (и то при условии, что эта дискета двойной плотности, иначе ее объем был 110 кб). Точнее на этой дискете еще должно было остаться место для операционной системы, файлового менеджера и рабочих файлов.&lt;br /&gt;&lt;br /&gt;С тех пор прошло много лет. Теперь просто программа выводящая "Hello World" будет занимать около 5 кб. И это в том случае, если она динамически связана с run-time библиотекой. Иначе, файлик скомпилированный g++ версии 4.1.3, весит больше 600 кб! Рассказ о том, что содержит такая программа - это отдельная история, и скорее всего уже неоднократно описанная. Для сравнения, в DOS такое занимало бы менее 20 байт. Не потому, что тогда не было run-time части, а потому, что программисты предпочитали assembler :-)&lt;br /&gt;&lt;br /&gt;Но те времена прошли. Теперь каждый вполне может позволить себе дома держать несколько терабайт информации. И если не держать коллекцию видео, то обычно пространства хватает, поэтому жаловаться на объем программ я не буду. Проблема заключается в другом. Из-за все возрастающего объема программы работают медленно. Гигагерцовые процессоры не способны показать свою скорость из-за того, что почти все современные программы потребляют слишком много ресурсов. Каждая новая версия медленней предыдущей. Многие программисты совершенно не задумываются о том, что какие-то вещи можно было бы сделать оптимальней. Золотое правило &lt;q&gt;Работает, не трогай&lt;/q&gt; не рекомендует вмешиваться в кем-то написанный код, т.к. последующая отладка и тестирование скорее всего обойдутся дороже, чем полученный выигрыш. Даже мой любимый vim не загружается моментально, как хотелось бы.&lt;br /&gt;&lt;br /&gt;Но даже медленную скорость можно стерпеть. Зато у нас есть новые возможности. Вот со стабильностью программ точно беда. И учитывая, что точно такие же программы работают в других железках, вроде плеера, мобильного телефона, маршрутизаторов, видео проигрывателей и т.д., то с ними возникают те же самые проблемы. На рынок выходят устройства, которые еще полностью не протестированы, и содержат ошибки. Например мой mp3 плеер при проигрывании песен иногда зацикливается на нескольких каталогах. Ждешь, что он будет играть все песни по порядку, а эта пакость какой-то один каталог все играет и играет до тех пор, пока не поймешь, что эту песню ты уже слышал много раз. Прошивка мобильника также содержит ошибки, которые были мной замечены в первые же дни использования. На днях в аэропорте Хитроу из-за ошибок в программах открытие 5-го терминала &lt;a href="http://www.osp.ru/news/articles/2008/13/4916074/"&gt;прошло с позором&lt;/a&gt;. Широкое распространение получают методы разработки программ, позволяющие выпускать продукты быстро, часто,  но при этом с ошибками. Несколько лет назад мне понравилась программа виртуализации &lt;a href="www.virtualbox.org/"&gt;VirtualBox&lt;/a&gt;. Но сколько я не пытался ее использовать (последний раз это было несколько месяцев назад на версии 1.5.6), она не выдерживает и суток при интесивной работе (конечно не ручной, а в качестве тестового стенда), обязательно падает. Приходится использовать более медленные, но более стабильные продукты VMWare. Некоторое время назад я писал об Eclipse, который тоже содержит большое количество ошибок. Получается, что покупая, мы приобретаем недоделанные и способные выполнять свои функции продукты. Очень жаль, что законом не предусмотрены штрафы и компенсации за такое свинство. Именно поэтому я предпочитаю ПО с открытыми исходными текстами. Ошибок также предостаточно, но чаще всего их можно исправить. С закрытым ПО это не получится.&lt;br /&gt;&lt;br /&gt;Интересно, как все это будет развиваться дальше. Программы используются и в банках, и в банкоматах, и в больницах, и во многих других местах, где любая ошибка может стоить очень и очень дорого. Конечно там ПО тестируется тщательней, но это не избавляет его от ошибок. &lt;br /&gt;&lt;br /&gt;Или может быть, воспоминания о том, как когда-то все было хорошо и красочно, просто признак старения? :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8536094954863042356-2417223838766142744?l=blog.nekipelov.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AlexNekipelovBlog/~4/_Ewu3_adev8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/2417223838766142744/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://blog.nekipelov.net/2008/04/blog-post_03.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/2417223838766142744?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/2417223838766142744?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AlexNekipelovBlog/~3/_Ewu3_adev8/blog-post_03.html" title="Размышления о современном ПО" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/11644484550750096086</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://1.bp.blogspot.com/-gF40tHGJFbk/TXMfXxe4Z2I/AAAAAAAAADM/Ovx7kQb5p_4/s220/%25D1%258F%2B%25D1%2581%2B%25D1%2581%25D0%25BE%25D0%25B1%25D0%25B0%25D0%25BA%25D0%25BE%25D0%25B9%2B%25D0%25BC%25D0%25B8%25D0%25BD%25D0%25B8.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nekipelov.net/2008/04/blog-post_03.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkQNRHk4eSp7ImA9WxZUEUs.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356.post-6997223869338955951</id><published>2008-04-02T11:33:00.000+04:00</published><updated>2008-04-03T00:33:15.731+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-04-03T00:33:15.731+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="http" /><category scheme="http://www.blogger.com/atom/ns#" term="оптимизация" /><category scheme="http://www.blogger.com/atom/ns#" term="web" /><title>Оптимизация доступности сайта</title><content type="html">Количество пользователей интернета растет с каждым днем. По крайней мере в России также растет и пропускная способность каналов. Это приводит к тому, что растет и нагрузка на сайты. А учитывая, что каждый старается завоевать как можно пользователей, на популярные сайты она растет еще сильнее. Раньше страницы старались оптимизировать для пользователей с модемным каналом в 32 - 56 кбит, а теперь же стараются привлекать интерактивностью, красивыми картинками... Это тоже приводит к повышению нагрузки. Таким образом через некоторое время любой относительно популярный сайт сталкивается с замедлением скорости отдачи контента пользователю. Не говоря уже о до сих пор актуальном &lt;a href="http://ru.wikipedia.org/wiki/%D0%A1%D0%BB%D1%8D%D1%88%D0%B4%D0%BE%D1%82-%D1%8D%D1%84%D1%84%D0%B5%D0%BA%D1%82"&gt;slashdot эффекте&lt;/a&gt;. А медленные сайты пользователям очень не нравятся. Поэтому чтобы иметь возможность расширять аудиторию дальше, необходима оптимизация.&lt;br /&gt;&lt;br /&gt;Я относительно недавно начал работу над небольшим web проектом с перспективой стать большим. Пока в качестве хостинга используется домашний сервер вот такой конфигурации: процессор Celeron 2,4 Ghz, 4 жестких диска по 500 Гб объединенные в RAID, 512 RAM. До этого момента сервер не испытывал больших нагрузок, поэтому такая конфигурация более чем устраивала. Начал задумываться о том, как оптимальней использовать доступные ресурсы и накопал в сети достаточно интересные статьи и решил поделиться ссылками.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://webo.in/articles/clientside2007/common-pages-optimization/"&gt;http://webo.in/articles/clientside2007/common-pages-optimization/&lt;/a&gt;&lt;br /&gt;&lt;em&gt;Оптимизация часто показываемых страниц. Александр Моисеев&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;Довольно интересные советы по оптимизации &lt;strong&gt;очень&lt;/strong&gt; часто показываемых страниц. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://webo.in/articles/habrahabr/03-presentation-layer-performance-tuning/"&gt;http://webo.in/articles/habrahabr/03-presentation-layer-performance-tuning/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Перевод очень хорошей статьи &lt;em&gt;"Оптимизируем загрузку веб-страницы"&lt;/em&gt;. К своему стыду должен признать, что только из этой статьи я впервые узнал о CDN (Content Delivery Networks). &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://webo.in/articles/habrahabr/08-all-about-css-sprites/ "&gt;http://webo.in/articles/habrahabr/08-all-about-css-sprites/&lt;/a&gt;&lt;br /&gt;&lt;em&gt;CSS Sprites: все, что вы знали, но боялись спросить&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;И похожая по смыслу &lt;a href="http://higher.com.ua/article/102/css-sprites-i-ikh-ispolzovanie"&gt;CSS Sprites и их использование&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;Мне кажется, что об этом способе оптимизации нужно известить многих разработчиков современных форумов. Потому, что количество всяческих картинок, смайликов, аватаров, элементов оформления, и на каждый свой запрос... Отбивает всякое желание заходить в такое форумы.&lt;br /&gt;&lt;br /&gt;На сайте &lt;a href="http://webo.in/"&gt;http://webo.in/&lt;/a&gt; имеется еще большое количество полезных статей, которые я возможно пропустил.&lt;br /&gt;&lt;br /&gt;Очень полезны правила, выработанные в yahoo: &lt;a href="http://developer.yahoo.com/performance/rules.html"&gt;Best Practices for Speeding Up Your Web Site&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Также полезно прочитать статьи об архитектуре высоконагруженных порталов. Или посмотреть доклады с конференции &lt;a href="http://highload1.rutube.ru/"&gt;HighLoad2007&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8536094954863042356-6997223869338955951?l=blog.nekipelov.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AlexNekipelovBlog/~4/47Nr-KGGlyE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/6997223869338955951/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://blog.nekipelov.net/2008/04/blog-post.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/6997223869338955951?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/6997223869338955951?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AlexNekipelovBlog/~3/47Nr-KGGlyE/blog-post.html" title="Оптимизация доступности сайта" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/11644484550750096086</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://1.bp.blogspot.com/-gF40tHGJFbk/TXMfXxe4Z2I/AAAAAAAAADM/Ovx7kQb5p_4/s220/%25D1%258F%2B%25D1%2581%2B%25D1%2581%25D0%25BE%25D0%25B1%25D0%25B0%25D0%25BA%25D0%25BE%25D0%25B9%2B%25D0%25BC%25D0%25B8%25D0%25BD%25D0%25B8.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nekipelov.net/2008/04/blog-post.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUIBRnY-eyp7ImA9WxZUEEU.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356.post-4567908535365383341</id><published>2008-04-01T12:56:00.000+04:00</published><updated>2008-04-02T02:05:57.853+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-04-02T02:05:57.853+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="юмор" /><title>1-ое апреля</title><content type="html">Сегодняшний мой день прошел как и все остальные. Проснулся, на работу, с работы домой. И только вечером, читая новости я начал подозревать, что что-то тут не то. Новости какие-то странные. И вот добравшись до новости о том, что разработчикам ядра Linux придется откатываться на 1,5 года назад я понял, в чем причина. Сегодня же первое апреля! И вот так у меня каждый год :-)&lt;br /&gt;&lt;br /&gt;Блог у меня задумывался как технический, но уверен, что немного юмора не помешает. Вот 1-апрельские новости, показавшиеся мне интересными.&lt;br /&gt;&lt;br /&gt;Традиционно больше всех шутит &lt;a href="http://www.securitylab.ru"&gt;www.securitylab.ru&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.securitylab.ru/news/349366.php"&gt;Ошибка в Linux чуть не привела к гибели всего человечества&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Чем могло обернуться возникновение миниатюрной черной дыры у такого насыщенного материей объекта, как планета Земля, нетрудно представить – поглощение материи растущей черной дырой было бы спонтанным, наша планета могла исчезнуть менее чем за две минуты.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.securitylab.ru/news/349322.php"&gt;Алексей Лукацкий будет отвечать за вживление чипов в мозг россиян&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;По словам Алексея Лукацкого, компания Cisco на днях подпишет соглашение с министерством Юстиции, в результате которого первые эксперименты по вживлению чипов в человека будут использоваться для контроля перемещения осужденных в Российских колониях.&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;По словам Алексея, если эксперимент будет признан успешным, то уже в следующем году можно ожидать массовую “чиповку мозгов” всем жителям России. Экспериментом также заинтересовался мэр Москвы Юрий Лужков, который выступает за более широкое использование данных чипов. Он предлагает внедрять чипы каждому мигранту или приезжему из других регионов в Москву, чтобы контролировать соблюдение законов о регистрации приезжих. В случае, если окажется что приезжий не смог легально зарегистрироваться в положенные сроки, мэр предлагает установить функцию блокировки мозга, в результате которой можно было бы легко вычислить нелегала среди настоящих москвичей.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.securitylab.ru/news/349379.php"&gt;У Mozilla Россия налоговые проблемы&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;В IT-сообществе уже ходят слухи о том, что эта проверка отнюдь не случайна. Считают, что конкуренты решили таким образом избавиться от соперника, или, как минимум, создать большие проблемы проекту Mozilla Россия.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;Да уж, налоговики совсем озверели... :-)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://linux.org.ru"&gt;Linux.org.ru&lt;/a&gt; тоже старается не отставать:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.linux.org.ru/view-message.jsp?msgid=2628014&amp;lastmod=1207081295312"&gt;Выпуск финальной версии Wine 1.0&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style='font-style: italic'&gt;&lt;br /&gt;После длительной разработки тихо и незаметно вышел wine 1.0. Среди кучи исправлений (как всегда) выделяют следующие:&lt;br /&gt;&lt;br /&gt;Работа Adobe Photoshop CS2, CS3, полная поддержка MS Office 2003 и 2007, полная поддержка OpenGL и DirectX.&lt;br /&gt;&lt;br /&gt;Особенностью данного релиза является включение кода WINE@Etersoft в основную ветку и поддержка 1С и Консультант+&lt;br /&gt;&lt;br /&gt;Презентация новой версии состоится 12 апреля на Microsoft Summer of Code. &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.linux.org.ru/view-message.jsp?msgid=2627605&amp;lastmod=1207069947507"&gt;Opera Software сфокусируется на музыкальном бизнесе&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style='font-style: italic'&gt;&lt;br /&gt;Так как в настоящее время компании Opera Software её кроссплатформенный браузер приносит менее 15% дохода, то компания решила сфокусироваться на музыкальном бизнесе и прекратить разработку браузера.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.linux.org.ru/view-message.jsp?msgid=2627294&amp;lastmod=1207070188264"&gt;VIA покупает AMD, NVidia и IBM&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style='font-style: italic'&gt;&lt;br /&gt;Как известно, новая 128-битная процессорная архитектура Isanah от компании VIA с поддержкой аппаратного квантового криптоанализа позволила компании быстро получить высокую прибыль за счёт крупных правительственных заказов.&lt;br /&gt;&lt;br /&gt;Т. о., циркулировавшие ранее слухи о том, что VIA собирается купить NVidia, а последняя собирается купить AMD, которая, в свою очередь, собирается слиться с IBM, нашли неожиданное подтверждение одновременно.&lt;br /&gt;&lt;br /&gt;Получившийся конгломерат VIA-AMD/ATI-NVIDIA/AGEIA-IBM, возможно, сможет составить хоть какую-нибудь конкуренцию Intel-Havok на микропроцессорном рынке.&lt;br /&gt;&lt;br /&gt;Так как продукция AMD, NVidia и IBM на настоящий момент обладает гораздо худшей производительностью, чем процессоры VIA Idinah и видеокарты VIA Chlame10, то скорее всего их продукция будет упразднена.&lt;br /&gt;&lt;br /&gt;Т. о., вопрос о поддержке новых высокопроизводительных графических карт от VIA под линуксом становится более актуальным.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Остальные сегодняшние новости я буду дочитывать завтра в метро, по пути на работу. Если встречу еще что-нибудь интересное, добавлю.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8536094954863042356-4567908535365383341?l=blog.nekipelov.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AlexNekipelovBlog/~4/wmzI6KnOTdU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/4567908535365383341/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://blog.nekipelov.net/2008/04/1.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/4567908535365383341?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/4567908535365383341?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AlexNekipelovBlog/~3/wmzI6KnOTdU/1.html" title="1-ое апреля" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/11644484550750096086</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://1.bp.blogspot.com/-gF40tHGJFbk/TXMfXxe4Z2I/AAAAAAAAADM/Ovx7kQb5p_4/s220/%25D1%258F%2B%25D1%2581%2B%25D1%2581%25D0%25BE%25D0%25B1%25D0%25B0%25D0%25BA%25D0%25BE%25D0%25B9%2B%25D0%25BC%25D0%25B8%25D0%25BD%25D0%25B8.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nekipelov.net/2008/04/1.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkUCSHYzfip7ImA9WxZVFkk.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356.post-8117651346321484700</id><published>2008-03-27T22:48:00.000+03:00</published><updated>2008-03-27T23:04:29.886+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-27T23:04:29.886+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="wince" /><category scheme="http://www.blogger.com/atom/ns#" term="pda" /><title>WinCE Frameworks</title><content type="html">К сожалению при выборе PDA пришлось купить машинку с установленной Windows CE. Подходящих по характеристикам PDA с предустановленным или возможностью установки Linux не нашлось. Поэтому использую то, что есть :-)&lt;br /&gt;&lt;br /&gt;Разумеется всего необходимого ПО я найти не смог. Что-то нужно делать самостоятельно. Т.к. времени у меня мало, писать на чистом WinAPI нет никакого желания. Первый выбор пал на .NET Framework и язык C#. Однако когда начал писать программы, оказалось, что Compact .NET Framework уж очень сильно обрезан по сравнению с обычной версией. Конечно понятно, чем руководствовались разработчики: .NET большой набор библиотек и все это сложно запихнуть на маленький PDA. Однако для меня, как разработчика, это очень неудобно. На мой взгляд, PDA обладает более чем достаточными возможностями и объемом памяти, для наличия полноценного Framework, максимально аналогичного десктопной версии.&lt;br /&gt;&lt;br /&gt;К счастью вспомнилось, что относительно недавно пробегала новость: наконец-то Qt Trolltech можно использовать и для приложений на Windows CE: &lt;a href="http://trolltech.com/developer/downloads/qt/qt-windows-ce"&gt;http://trolltech.com/developer/downloads/qt/qt-windows-ce&lt;/a&gt;.   К сожалению пока только в статусе &lt;strong&gt;Beta&lt;/strong&gt; и портирована не полностью. И только что взял &lt;a href="http://www.wxwidgets.org/"&gt;wxWidgets&lt;/a&gt; и заметил среди каталогов &lt;strong&gt;wince&lt;/strong&gt;. Нужно будет опробовать в работе.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8536094954863042356-8117651346321484700?l=blog.nekipelov.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AlexNekipelovBlog/~4/GDoi2Ag_4uE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/8117651346321484700/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://blog.nekipelov.net/2008/03/wince-frameworks.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/8117651346321484700?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/8117651346321484700?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AlexNekipelovBlog/~3/GDoi2Ag_4uE/wince-frameworks.html" title="WinCE Frameworks" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/11644484550750096086</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://1.bp.blogspot.com/-gF40tHGJFbk/TXMfXxe4Z2I/AAAAAAAAADM/Ovx7kQb5p_4/s220/%25D1%258F%2B%25D1%2581%2B%25D1%2581%25D0%25BE%25D0%25B1%25D0%25B0%25D0%25BA%25D0%25BE%25D0%25B9%2B%25D0%25BC%25D0%25B8%25D0%25BD%25D0%25B8.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nekipelov.net/2008/03/wince-frameworks.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkUFQno9fyp7ImA9WxZVFk0.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356.post-6898298546257882785</id><published>2008-03-27T10:21:00.001+03:00</published><updated>2008-03-27T10:50:13.467+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-27T10:50:13.467+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="IDE" /><category scheme="http://www.blogger.com/atom/ns#" term="eclipse" /><title>Впечатления от Eclipse</title><content type="html">На работе давно задумывали сделать нашу разработку кроссплатформенной и отказаться от привязки к Windows и Microsoft Visual Studio. Естественно в первую очередь я начал глядеть в сторону Eclipse. Использовал в течении месяца. Накопилось большое количество впечатлений, к сожалению, большей частью  отрицательных. Работает очень медленно (хотя MS VS тоже не блещет скоростью), выдает совершенно не понятные ошибки. Может быть человеку, который занимается разработкой на Java эти ошибки и понятны, однако я этот язык не знаю и знать не хочу. Поэтому Java исключения со стеком вызова мне мало о чем говорят.&lt;br /&gt;&lt;br /&gt;Сначала Eclipse отказывался запускаться. Точнее отказывался запускаться с помощью eclipse.exe, только eclipsec.exe, который оставляет консольное окно. Ладно, стерпел... но через некоторое время и он перестал запускаться. Полез в форумы, оказалось, что нужно поправить eclise.ini. Сделал. Некоторое время работало, через некоторое время опять запуск можно было осуществлять только через eclipsec.exe. И разумеется позже и этот способ перестал работать. Опять полез в форумы, там советовали запускать сразу указывая workspace. Написал .bat файл, запускающий eclipse с указанием workspace. Вроде работало. При этом если писать start eclipse -data "...", то опять возникает исключение.&lt;br /&gt;&lt;br /&gt;Вообще всяческих исключений почему-то происходило очень много. И при редактировании свойств проекта, иногда при компиляции... &lt;br /&gt;&lt;br /&gt;Попытка использовать отладчик тоже принесла много впечатлений. Если при запуске отладчика gdb в его консоли видны все сообщения, то почему-то при отладке в eclipse консоль отладчика была пустой.   При этом eclipse усердно пытался дать мне .cpp файл совершенно не того проекта, что я запускал. Поставил галочку предлагающую выбирать файл исходных текстов при совпадении имени, так и она работала через раз. Позже выяснилось, что в списке исходных текстов текущий проект должен быть первым.&lt;br /&gt;&lt;br /&gt;В общем было очень много возни, неадекватного поведения, и совершенно ужасного usability.&lt;br /&gt;&lt;br /&gt;Хотя при использовании Eclipse под Linux проблем было гораздо меньше. Но я не смогу сказать директору, что наши программисты должны мучиться с этой ужасной вещью. К сожалению придется искать что-то другое. Для себя я бы однозначно выбрал vim/gvim, однако большинству нужна IDE в стиле Visual Studio. Может быть, когда KDE полностью портируют на Windows, KDevelop справится с этой задачей? А пока попробую Netbeans.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8536094954863042356-6898298546257882785?l=blog.nekipelov.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AlexNekipelovBlog/~4/DfS0q1v_1vg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/6898298546257882785/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://blog.nekipelov.net/2008/03/eclipse.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/6898298546257882785?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/6898298546257882785?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AlexNekipelovBlog/~3/DfS0q1v_1vg/eclipse.html" title="Впечатления от Eclipse" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/11644484550750096086</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://1.bp.blogspot.com/-gF40tHGJFbk/TXMfXxe4Z2I/AAAAAAAAADM/Ovx7kQb5p_4/s220/%25D1%258F%2B%25D1%2581%2B%25D1%2581%25D0%25BE%25D0%25B1%25D0%25B0%25D0%25BA%25D0%25BE%25D0%25B9%2B%25D0%25BC%25D0%25B8%25D0%25BD%25D0%25B8.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nekipelov.net/2008/03/eclipse.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0MHRHk6eSp7ImA9WxZVEkk.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356.post-8514847112597490486</id><published>2008-03-23T07:50:00.000+03:00</published><updated>2008-03-23T08:17:15.711+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-23T08:17:15.711+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="размышления" /><category scheme="http://www.blogger.com/atom/ns#" term="utf8" /><title>переход на UTF8</title><content type="html">Странно затягивается переход к универсальной кодировке символов. С одной стороны, нам достаточно надоело тяжелое наследие в виде большого количество разнообразных кодировок, с другой, не смотря на большое количество прошедшего времени, нельзя сказать, что все основное ПО работает с многобайтовыми кодировками.&lt;br /&gt;&lt;br /&gt;Около месяца назад я изменил локаль в Linux с koi8-r на utf8. Проблем почти не возникло. Разве что firefox (точнее Iceweasel) при сохранении файлов с русскими именами делает это криво. Теперь начал и всю обработку текстовой информации вести utf8. И вот тут уже начались проблемы. Сначала пришлось помучиться, чтобы заставить mysql учитывать русский текст при поиске/сортировке (а вот с PostgreSQL никаких проблем не возникло). Потом оказалось, что многие мои утилитки, использующие другие утилитки, не могут работать с utf8. Например сейчас столкнулся с тем, что в HTML::Parser (модуль из языка perl) есть такой код:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sub parse_file&lt;br /&gt;{&lt;br /&gt;    my($self, $file) = @_;&lt;br /&gt;    my $opened;&lt;br /&gt;    if (!ref($file) &amp;&amp; ref(\$file) ne "GLOB") {&lt;br /&gt;        # Assume $file is a filename&lt;br /&gt;        local(*F);&lt;br /&gt;        open(F, $file) || return undef;&lt;br /&gt;        binmode(F);  # should we? good for byte counts&lt;br /&gt;        $opened++;&lt;br /&gt;        $file = *F;&lt;br /&gt;    }&lt;br /&gt;    my $chunk = '';&lt;br /&gt;    while (read($file, $chunk, 512)) {&lt;br /&gt;        $self-&gt;parse($chunk) || last;&lt;br /&gt;    }&lt;br /&gt;    close($file) if $opened;&lt;br /&gt;    $self-&gt;eof;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Чтение равно по 512 байт приводит к тому, что в многобайтовой кодировке может прочитаться только част байт символа. Ну, это не большая проблема, решение там описано. Только почему-то HTML::TreeBuilder коверкает часть особых символов, но мне уже надоело разбираться, лучше перепишу это на ruby.&lt;br /&gt;&lt;br /&gt;На работе у меня в плане полное перепроектирование системы, разработкой которой я занимаюсь. Она  наконец-то станет кросс-платформенной. Соответственно исходники следует перевести в utf8. Интересно, коллеги сильно обидятся, если столкнуться с подобными проблемами? :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8536094954863042356-8514847112597490486?l=blog.nekipelov.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AlexNekipelovBlog/~4/np18hlTh2H8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/8514847112597490486/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://blog.nekipelov.net/2008/03/utf8.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/8514847112597490486?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/8514847112597490486?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AlexNekipelovBlog/~3/np18hlTh2H8/utf8.html" title="переход на UTF8" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/11644484550750096086</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://1.bp.blogspot.com/-gF40tHGJFbk/TXMfXxe4Z2I/AAAAAAAAADM/Ovx7kQb5p_4/s220/%25D1%258F%2B%25D1%2581%2B%25D1%2581%25D0%25BE%25D0%25B1%25D0%25B0%25D0%25BA%25D0%25BE%25D0%25B9%2B%25D0%25BC%25D0%25B8%25D0%25BD%25D0%25B8.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nekipelov.net/2008/03/utf8.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak8BR34-fSp7ImA9WxZbGUU.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356.post-4224834501205184579</id><published>2008-03-22T02:55:00.000+03:00</published><updated>2008-04-24T02:14:16.055+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-04-24T02:14:16.055+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="fictionbook" /><category scheme="http://www.blogger.com/atom/ns#" term="perl" /><category scheme="http://www.blogger.com/atom/ns#" term="patch" /><title>fb2-tools-perl: обработка изображений скриптом html2fb2.pl</title><content type="html">Появилась у меня необходимость связаться со скриптами из проекта &lt;a href="http://fb2-perl-tools.sourceforge.net/"&gt;http://fb2-perl-tools.sourceforge.net/&lt;/a&gt; - это набор скриптов для конвертации книг из/в формат &lt;a href="http://ru.wikipedia.org/wiki/Fictionbook"&gt; Fictionbook&lt;/a&gt;. Мне нужно было конвертировать html файл в fb. Все бы хорошо, только изображения игнорировались. Пришлось, как всегда, приложить руку.&lt;br /&gt;&lt;br /&gt;&lt;span class="through"&gt;Результат можно взять &lt;a href="http://nekipelov.homeunix.net/files/html2fb2.pl-images.patch"&gt;тут&lt;/a&gt; в виде патча.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;UPDATE 2008-04-24: Патч был включен в репозиторий проекта, поэтому убираю его с сервера.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8536094954863042356-4224834501205184579?l=blog.nekipelov.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AlexNekipelovBlog/~4/qbgsfjsHkSA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/4224834501205184579/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://blog.nekipelov.net/2008/03/fb2-tools-perl.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/4224834501205184579?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/4224834501205184579?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AlexNekipelovBlog/~3/qbgsfjsHkSA/fb2-tools-perl.html" title="fb2-tools-perl: обработка изображений скриптом html2fb2.pl" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/11644484550750096086</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://1.bp.blogspot.com/-gF40tHGJFbk/TXMfXxe4Z2I/AAAAAAAAADM/Ovx7kQb5p_4/s220/%25D1%258F%2B%25D1%2581%2B%25D1%2581%25D0%25BE%25D0%25B1%25D0%25B0%25D0%25BA%25D0%25BE%25D0%25B9%2B%25D0%25BC%25D0%25B8%25D0%25BD%25D0%25B8.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nekipelov.net/2008/03/fb2-tools-perl.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEEGQHw5eCp7ImA9WxZVEk0.&quot;"><id>tag:blogger.com,1999:blog-8536094954863042356.post-1423181172703144663</id><published>2008-03-22T02:45:00.000+03:00</published><updated>2008-03-22T19:17:01.220+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-22T19:17:01.220+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="всякое" /><title>Первое сообщение</title><content type="html">Я начал задумываться о создании своего блога еще где-то с 2000 года. В то время мода на них только пошла мода. Но к сожалению вечное отсутствие свободного времени не позволяло мне этого сделать.  Хотя сейчас свободного времени у меня еще меньше, я все-таки решил выделить некоторое его количество на написание полезной (на мой взгляд) информации.&lt;br /&gt;&lt;br /&gt;Этот блог будет совсем не о событиях в моей жизни, скорее строго технический. Интересов у меня много, поэтому и информация будет разнообразная, но большей частью по web и программированию. Надеюсь, что кому-нибудь она тоже покажется полезной.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8536094954863042356-1423181172703144663?l=blog.nekipelov.net' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/AlexNekipelovBlog/~4/dQoKSnZ-fU8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nekipelov.net/feeds/1423181172703144663/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://blog.nekipelov.net/2008/03/blog-post.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/1423181172703144663?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8536094954863042356/posts/default/1423181172703144663?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/AlexNekipelovBlog/~3/dQoKSnZ-fU8/blog-post.html" title="Первое сообщение" /><author><name>Alex Nekipelov</name><uri>http://www.blogger.com/profile/11644484550750096086</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="31" height="32" src="http://1.bp.blogspot.com/-gF40tHGJFbk/TXMfXxe4Z2I/AAAAAAAAADM/Ovx7kQb5p_4/s220/%25D1%258F%2B%25D1%2581%2B%25D1%2581%25D0%25BE%25D0%25B1%25D0%25B0%25D0%25BA%25D0%25BE%25D0%25B9%2B%25D0%25BC%25D0%25B8%25D0%25BD%25D0%25B8.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nekipelov.net/2008/03/blog-post.html</feedburner:origLink></entry></feed>

