<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="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" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-8518171411908930166</atom:id><lastBuildDate>Thu, 09 Feb 2012 04:07:16 +0000</lastBuildDate><category>dv capture</category><category>bufferevent</category><category>fifo</category><category>postgresql</category><category>stdio</category><category>качество кода</category><category>avcap</category><category>рекламная система</category><category>C</category><category>thread-safe</category><category>libc</category><category>http</category><category>документация</category><category>kqueue</category><category>ab</category><category>qnx</category><category>vsnprintf()</category><category>openx</category><category>Platform SDK</category><category>буферизированный ввод/вывод</category><category>ведение логов</category><category>ошибки</category><category>сборка</category><category>код</category><category>сетевая разработка</category><category>wdh</category><category>libpqxx</category><category>wxWidgets</category><category>snprintf()</category><category>pure virtual call</category><category>warnings</category><category>обновление</category><category>Windows SDK</category><category>rpc</category><category>BaseClasses</category><category>codecamp</category><category>журналирование</category><category>callback</category><category>протокол</category><category>API</category><category>вебинар</category><category>эхо-сервер</category><category>databases</category><category>асинхронный ввод/вывод</category><category>встречи</category><category>openss</category><category>libevent</category><category>wxLog</category><category>openads</category><category>data access</category><category>ОСРВ</category><category>ssl</category><category>сервер</category><category>чтение кода</category><category>highload</category><category>DirectX</category><category>конференция</category><category>баг</category><title>In C++</title><description>Использование языка C/C++ в разработке</description><link>http://incpp.blogspot.com/</link><managingEditor>noreply@blogger.com (Андрей Булавинов)</managingEditor><generator>Blogger</generator><openSearch:totalResults>19</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/rss+xml" href="http://feeds.feedburner.com/blogspot/InCpp" /><feedburner:info uri="blogspot/incpp" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8518171411908930166.post-2623610325647431843</guid><pubDate>Fri, 05 Nov 2010 21:24:00 +0000</pubDate><atom:updated>2010-11-05T23:24:49.837+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">openss</category><category domain="http://www.blogger.com/atom/ns#">ssl</category><title>Использование OpenSSL</title><description>&lt;h2 id="internal-source-marker_0.939554652114359" style="font-family: inherit; margin-bottom: 0pt; margin-top: 0pt; text-align: center;"&gt;&lt;span style="background-color: transparent; color: black; font-size: large; font-style: normal; font-weight: bold; text-decoration: none; vertical-align: baseline;"&gt;Часть 1. Сборка и подключение&lt;/span&gt;&lt;/h2&gt;&lt;span style="background-color: transparent; color: black; font-family: inherit; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style="font-family: inherit; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;Чтобы добавить поддержку шифрования в сетевое приложение можно воспользоваться открытой библиотекой OpenSSL.&lt;/span&gt;&lt;/div&gt;&lt;span style="background-color: transparent; color: black; font-family: inherit; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;h3 style="font-family: inherit; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="background-color: transparent; color: black; font-size: large; font-style: normal; font-weight: bold; text-decoration: none; vertical-align: baseline;"&gt;1. Сборка библиотеки&lt;/span&gt;&lt;/h3&gt;&lt;span style="background-color: transparent; color: black; font-family: inherit; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style="font-family: inherit; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;Поскольку  бинарные сборки библиотеки доступны не для всех архитектур — будем  собирать из исходников. Тем более, что это позволит использовать  подходящие флаги оптимизации.&lt;/span&gt;&lt;/div&gt;&lt;span style="background-color: transparent; color: black; font-family: inherit; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;h4 style="font-family: inherit; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="background-color: transparent; color: black; font-size: 12pt; font-style: normal; font-weight: bold; text-decoration: none; vertical-align: baseline;"&gt;1.1 Unix&lt;/span&gt;&lt;/h4&gt;&lt;span style="background-color: transparent; color: black; font-family: inherit; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style="font-family: inherit; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;Сборка  под Unix достаточно тривиальна, особенно, если в нашем распоряжении  есть менеджер пакетов. Но, на всякий случай, приведу последовательность  сборки из исходников.&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: inherit; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;Качаем последнюю (или необходимую) версию по адресу &lt;/span&gt;&lt;a href="http://www.openssl.org/source/"&gt;&lt;span style="background-color: transparent; color: #000099; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: underline; vertical-align: baseline;"&gt;http://www.openssl.org/source/&lt;/span&gt;&lt;/a&gt;&lt;span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt; и распаковываем ее. На данный момент последняя версия — openssl-1.0.0a:&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="background-color: #cccccc; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&amp;gt; tar xvpf openssl-1.0.0a.tar.gz&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style="font-family: inherit; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;В каталоге ./openssl-1.0.0a/ запускаем скрипт конфигурации:&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;span style="background-color: #cccccc; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style="margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="background-color: #cccccc; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&amp;gt; ./config&lt;/span&gt;&lt;span style="background-color: #cccccc; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="background-color: #cccccc; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt; &lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: inherit; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;Собираем:&lt;/span&gt;&lt;/div&gt;&lt;span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;br /&gt;
&lt;div style="margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="background-color: #cccccc; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&amp;gt; make&lt;/span&gt;&lt;/div&gt;&lt;span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;br /&gt;
&lt;div style="margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&lt;span style="font-family: inherit;"&gt;И устанавливаем:&lt;/span&gt;&lt;br class="kix-line-break" /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="background-color: #cccccc; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&amp;gt; sudo make install&lt;/span&gt;&lt;/div&gt;&lt;span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-family: inherit;"&gt;Проверить работоспособность и версию установленной библиотеки можно выполнив команду:&lt;/span&gt;&lt;br class="kix-line-break" /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;br /&gt;
&lt;div style="margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="background-color: #cccccc; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&lt;span style="background-color: #cccccc;"&gt;&amp;gt; openssl version&lt;/span&gt;&lt;span&gt;&lt;span style="background-color: #cccccc;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;br /&gt;
&lt;h4 style="font-family: inherit; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="background-color: transparent; color: black; font-size: 12pt; font-style: normal; font-weight: bold; text-decoration: none; vertical-align: baseline;"&gt;1.2 Windows&lt;/span&gt;&lt;/h4&gt;&lt;span style="background-color: transparent; color: black; font-family: inherit; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: transparent; color: black; font-family: inherit; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Под Windows нам понадобится чуть больше движений. Для конфигурирования необходим Perl, который можно взять здесь &lt;/span&gt;&lt;a href="https://docs.google.com/document/d/1pHHgSAVGHIB3mAIWl2n4XlzcNrlDbBc3ZXbiYsyxqEs/edit" style="font-family: inherit;"&gt;&lt;span style="background-color: transparent; color: #000099; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: underline; vertical-align: baseline;"&gt;(http://strawberryperl.com/)&lt;/span&gt;&lt;/a&gt;&lt;span style="background-color: transparent; color: black; font-family: inherit; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt; и для сборки — Visual Studio с компилятором C++.&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: transparent; color: black; font-family: inherit; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; После установки перечисленных выше пакетов, можно приступать к сборке.&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: transparent; color: black; font-family: inherit; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;  В командной строке переходим в каталог openssl-1.0.0a и выполняем и  запускаем Perl с указанием компилятора и каталога, в который будет  установлена собранная библиотека:&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style="background-color: #cccccc;"&gt;&lt;span style="background-color: #cccccc; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;gt; perl Configure VC-WIN32 --prefix=c:\Temp\openssl&lt;br class="kix-line-break" /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;gt; ms\do_ms &lt;/span&gt;&lt;/div&gt;&lt;div style="background-color: #cccccc;"&gt;&lt;span style="background-color: #cccccc; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="font-family: inherit;"&gt; Если последней строчкой будет: &lt;/span&gt;&lt;/span&gt;&lt;span style="background-color: transparent; color: black; font-family: inherit; font-size: 11pt; font-style: normal; font-weight: bold; text-decoration: none; vertical-align: baseline;"&gt;Configured for VC-WIN32&lt;/span&gt;&lt;span style="background-color: transparent; color: black; font-family: inherit; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt; — значит все хорошо, если нет — ищем ошибку, исправляем и повторяем процедуру.&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: transparent; color: black; font-family: inherit; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Теперь компиляция. Запускаем &lt;/span&gt;&lt;span style="background-color: transparent; color: black; font-family: inherit; font-size: 11pt; font-style: normal; font-weight: bold; text-decoration: none; vertical-align: baseline;"&gt;Visual Studio 2008 Command Prompt&lt;/span&gt;&lt;span style="background-color: transparent; color: black; font-family: inherit; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt; в каталоге с openssl и запускаем сборку. &lt;/span&gt;&lt;br /&gt;
&lt;div style="font-family: inherit; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;Чтобы получить DLL:&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="background-color: #cccccc; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&lt;/span&gt;&lt;span style="color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&amp;gt; nmake -f ms\ntdll.mak&lt;/span&gt;&lt;/div&gt;&lt;div style="background-color: #cccccc; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&amp;gt; nmake -f ms\ntdll.mak install&lt;/span&gt;&lt;/div&gt;&lt;span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;br /&gt;
&lt;div style="font-family: inherit; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;Чтобы собрать статическую библиотеку:&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="background-color: #cccccc; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&amp;gt; nmake -f ms\nt.mak&lt;/span&gt;&lt;span style="color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="background-color: #cccccc; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&amp;gt; &lt;/span&gt;&lt;span style="color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;nmake -f ms\nt.mak install&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;
&lt;h3&gt;&lt;span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14pt; font-style: normal; font-weight: bold; text-decoration: none; vertical-align: baseline;"&gt;&amp;nbsp;&lt;span style="font-family: inherit;"&gt;&amp;nbsp;&amp;nbsp; 2. Подключение&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;&lt;span style="background-color: transparent; color: black; font-family: inherit; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: transparent; color: black; font-family: inherit; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;  После того, как библиотека была успешно собрана и установлена, ее можно  начинать использовать. Нам понадобятся заголовочные файлы и сама  библиотека.&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: transparent; color: black; font-family: inherit; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;В Unix это тривиальное &lt;/span&gt;&lt;span style="background-color: transparent; color: black; font-family: inherit; font-size: 11pt; font-style: normal; font-weight: bold; text-decoration: none; vertical-align: baseline;"&gt;-lssl&lt;/span&gt;&lt;span style="background-color: transparent; color: black; font-family: inherit; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;  во флагах линковщика, а в Windows необходимо указать путь к  заголовочным файлам, собранной библиотеке и указать имена библиотек:&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="background-color: #cccccc; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;Additional Include Directories: &lt;/span&gt;&lt;span style="background-color: #cccccc; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: bold; text-decoration: none; vertical-align: baseline;"&gt;c:/Temp/openssl/include&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="background-color: #cccccc; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: bold; text-decoration: none; vertical-align: baseline;"&gt;&lt;/span&gt;&lt;span style="background-color: #cccccc; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;Additional Library Directories: &lt;/span&gt;&lt;span style="background-color: #cccccc; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: bold; text-decoration: none; vertical-align: baseline;"&gt;c:/Temp/openssl/lib&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&lt;/span&gt;&lt;span style="background-color: #cccccc; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;Additional Dependencies: &lt;/span&gt;&lt;span style="background-color: #cccccc; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: bold; text-decoration: none; vertical-align: baseline;"&gt;libeay32.lib ssleay32.lib&lt;/span&gt;&lt;span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style="font-family: inherit; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;span style="background-color: transparent; color: black; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"&gt;Теперь можно использовать функции OpenSSL в проекте. Как добавить шифрование в сервер и клиент я расскажу в следующей части.&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;a href="http://incpp.blogspot.com/"&gt;In C++. Программирование на C++ и не только...&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8518171411908930166-2623610325647431843?l=incpp.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/InCpp/~4/q7wvKXDhMOA" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/InCpp/~3/q7wvKXDhMOA/openssl.html</link><author>noreply@blogger.com (Андрей Булавинов)</author><thr:total>3</thr:total><feedburner:origLink>http://incpp.blogspot.com/2010/11/openssl.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8518171411908930166.post-4147193601318466958</guid><pubDate>Fri, 29 Jan 2010 10:31:00 +0000</pubDate><atom:updated>2010-01-29T12:31:03.177+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">C</category><category domain="http://www.blogger.com/atom/ns#">libc</category><category domain="http://www.blogger.com/atom/ns#">snprintf()</category><category domain="http://www.blogger.com/atom/ns#">vsnprintf()</category><category domain="http://www.blogger.com/atom/ns#">stdio</category><title>Исключения в C</title><description>Используя возможности библиотеки C, а точнее средства stdio, необходимо быть особо внимательным, когда используешь результаты возврата функций.&lt;br /&gt;
&lt;br /&gt;
Функции printf(), vprintf(), fprintf(), vfprintf(), sprintf(), vsprintf(), asprintf(), vasprintf() — возвращают &lt;b&gt;количество записанных&lt;/b&gt; байт,&lt;br /&gt;
а функции &lt;b&gt;snprintf()&lt;/b&gt; и &lt;b&gt;vsnprintf()&lt;/b&gt; — &lt;b&gt;количество&lt;/b&gt; байт, &lt;b&gt;которое могло бы быть записаным&lt;/b&gt;, если бы размер буфера был неограниченный! Эти функции &lt;b&gt;гарантировано&lt;/b&gt; &lt;b&gt;возвращают&lt;/b&gt; &lt;b&gt;NULL-терминированную строку&lt;/b&gt;, если не произошло ошибки.&lt;div class="blogger-post-footer"&gt;&lt;a href="http://incpp.blogspot.com/"&gt;In C++. Программирование на C++ и не только...&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8518171411908930166-4147193601318466958?l=incpp.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/InCpp/~4/J3Uj5dW-uqk" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/InCpp/~3/J3Uj5dW-uqk/c.html</link><author>noreply@blogger.com (Андрей Булавинов)</author><thr:total>0</thr:total><feedburner:origLink>http://incpp.blogspot.com/2010/01/c.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8518171411908930166.post-1318103190233200726</guid><pubDate>Tue, 01 Dec 2009 16:51:00 +0000</pubDate><atom:updated>2009-12-01T19:31:01.646+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">bufferevent</category><category domain="http://www.blogger.com/atom/ns#">сетевая разработка</category><category domain="http://www.blogger.com/atom/ns#">libevent</category><category domain="http://www.blogger.com/atom/ns#">буферизированный ввод/вывод</category><title>Буферизированный ввод/вывод средствами libevent</title><description>Разрабатывая сетевые приложения, часто сталкиваешься с необходимостью работать с пакетами данных на уровне,&lt;br /&gt;который находится чуть выше чем потоковый. Удобно, когда при отправке пакета информации на стороне клиента&lt;br /&gt;сервер получает этот пакет за один раз и асинхронно относительно других клиентов.&lt;br /&gt;   Техническая реализация сетевого стека и API для работы с ним такова, что в асинхронном режиме работы с сокетами&lt;br /&gt;вызов send(2) и read(2) не обязательно отправляют или принимают полный пакет, лишь только тот объем, который&lt;br /&gt;в текущий момент доступен. В синхронном (блокирующем) режиме возникает другое ограничение — выполнение программы&lt;br /&gt;приостанавливается, пока не будет отправлено или вычитано указанное количество байт, что мешает одновременно работать&lt;br /&gt;сразу со многими подключениями в одном потоке. Решение этой проблемы можно найти, например, в библиотеке libevent.&lt;br /&gt;   Библиотека libevent, помимо классических обратных вызовов (callbacks) по событиям, предоставляет абстракцию,&lt;br /&gt;которая буферизирует все вызовы чтения/записи (buffered event) [1]. Такой механизм обеспечивает автоматическое&lt;br /&gt;заполнение и освобождение буферов при операциях чтения и записи.&lt;br /&gt;Для того, чтобы начать работать с буферизированным вводом/выводом необходимо:&lt;br /&gt;— инициализировать структуру bufferevent вызовом bufferevent_new(), указав функции для обратного вызова на события  чтения (необязательно), записи (необязательно) и ошибки (обязательно) ;&lt;br /&gt;— Привязать это событие к локальной событийной базе (event_base) вызовом bufferevent_base_set();&lt;br /&gt;— Включать или выключать обработчики чтения/записи вызовами bufferevent_enable()/bufferevent_disable();&lt;br /&gt;— Читать и писать вызовами bufferevent_read() и bufferevent_write() соответственно.&lt;br /&gt;Стоит отметить, что обработчик чтения будет вызван после того, как в буфере накопится весь пакет или закроется подключение,&lt;br /&gt;а обработчик записи — когда отправляемый буфер отправлен либо полностью, либо до указанной отметки (watermark).&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Пример использования&lt;/h3&gt;&lt;br /&gt;   Для примера напишем эхо-сервер и простой клиент, который будет обслуживать одновременно несколько клиентов.&lt;br /&gt;Начнем с сервера. Для этого нам понадобится слушающий сокет, который может асинхронно принимать подключения,&lt;br /&gt;обработчик подключения и логика работы с клиентом.&lt;br /&gt;   Для создания серверного сокета достаточно воспользоваться этой статьей.&lt;br /&gt;Для удобства, вся информация о подключениях хранится в хэш-таблице, которая завернута в класс Connections.&lt;br /&gt;Функция main будет практически идентичной, за исключением инициализации событийной базы:&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;   // Initialize&lt;br /&gt;   event_base * base = event_base_new();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Создается новая событийная база для того, чтобы не перекрывать глобальный контекст.&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;   // Init events&lt;br /&gt;   struct event ev;&lt;br /&gt;   // Set connection callback (on_connect()) to read event on server socket&lt;br /&gt;   event_set(&amp;amp;ev, server_sock, EV_READ | EV_PERSIST, on_connect, base);&lt;br /&gt;   // Attach event to new event base&lt;br /&gt;   event_base_set(base, &amp;amp;ev);&lt;br /&gt;   // Add server event without timeout&lt;br /&gt;   event_add(&amp;amp;ev, NULL);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Создается событие, которое реагирует на чтение из серверного сокета — это событие подключение нового клиента.&lt;br /&gt;Функция event_base_set — привязывает это событие к событийной базе.&lt;br /&gt;Обработка событий выполняется так:&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;   // Dispatch events&lt;br /&gt;   event_base_loop(base, 0);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Обработка подключения заключается в том, чтоб создать новое буферизированное событие, связанное с сокетом клиента.&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;   // Setup connection&lt;br /&gt;   ConnectionData &amp;amp; cdata = Connections::Instance().Add(sock);&lt;br /&gt;&lt;br /&gt;   cdata.evb = bufferevent_new(sock, on_read, on_write, on_error, arg);&lt;br /&gt;   bufferevent_base_set(reinterpret_cast&lt;event_base*&gt;(arg), cdata.evb);&lt;br /&gt;   // Ready to get data&lt;br /&gt;   bufferevent_enable(cdata.evb, EV_READ);&lt;br /&gt;&lt;/event_base*&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Чтение выполняется в функции on_read примерно следующим образом:&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;   size_t    len = EVBUFFER_LENGTH(evb-&gt;input);&lt;br /&gt;   u_char * data = new u_char[len];&lt;br /&gt;   size_t   read = bufferevent_read(evb, data, len);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Обработка отключения выполняется в функции on_error: необходимо проверить флаг EVBUFFER_EOF переменной what.&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;   if (what &amp;amp; EVBUFFER_EOF) {&lt;br /&gt;       // Disconnected&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;   В клиентской части работа с буферизированными событиями — аналогична. После выполнение подключения к серверу, инициализируем буфер:&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;   event_base  * base = event_base_new();&lt;br /&gt;   bufferevent * evb  = bufferevent_new(sfd, on_read, on_write, on_error, base);&lt;br /&gt;&lt;br /&gt;   bufferevent_base_set(base, evb);&lt;br /&gt;   bufferevent_enable(evb, EV_WRITE | EV_READ);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Стоит отметить, что создание буфера и запись в него осуществляется до вызова обработчика очереди событий:&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;   const char * data1 = "Hello from client";&lt;br /&gt;   bufferevent_write(evb, data1, strlen(data1) + 1);&lt;br /&gt;&lt;br /&gt;   event_base_loop(base, 0);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Обработка событий чтения/записи/ошибок аналогична обработке в серверной части.&lt;br /&gt;Работающий пример эхо-сервера и клиента можно взять &lt;a href="http://depositfiles.com/files/klhimi6yk"&gt;здесь&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;___&lt;br /&gt;1. &lt;a href="http://www.monkey.org/%7Eprovos/libevent/doxygen-1.4.10/"&gt;http://www.monkey.org/~provos/libevent/doxygen-1.4.10/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;a href="http://incpp.blogspot.com/"&gt;In C++. Программирование на C++ и не только...&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8518171411908930166-1318103190233200726?l=incpp.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/InCpp/~4/3nd9e992k1o" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/InCpp/~3/3nd9e992k1o/libevent.html</link><author>noreply@blogger.com (Андрей Булавинов)</author><thr:total>3</thr:total><feedburner:origLink>http://incpp.blogspot.com/2009/12/libevent.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8518171411908930166.post-1753059781991602627</guid><pubDate>Fri, 10 Jul 2009 09:22:00 +0000</pubDate><atom:updated>2009-07-13T22:52:25.246+03:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">рекламная система</category><category domain="http://www.blogger.com/atom/ns#">highload</category><category domain="http://www.blogger.com/atom/ns#">openx</category><category domain="http://www.blogger.com/atom/ns#">openads</category><title>Архитектура рекламной системы</title><description>Вопрос разработки высоконагруженных систем является очень актуальным. лично для меня, с&amp;nbsp;точки зрения ресурсопотребления.&lt;br /&gt;Можно спроектировать систему так, чтобы она хорошо масштабировалась горизонтально, но&amp;nbsp;она все равно будет расходовать слишком много ресурсов для решения поставленных для нее задач. В&amp;nbsp;качестве примера такой системы могу привести всем известный OpenX (бывший OpenAds) [1].&lt;br /&gt;Реальная ситуация: для открутки 10&amp;nbsp;баннеров, при нагрузке в&amp;nbsp;чуть более чем 4.5&amp;nbsp;миллиона показа в&amp;nbsp;сутки, система на&amp;nbsp;5&amp;nbsp;серверах (2х&amp;nbsp;процессорные машины с&amp;nbsp;4GB RAM) задыхается в&amp;nbsp;Load Average 200%. Оптимизации базы данных (LOAD DATA INFILE + кэширование) ситуацию сильно не&amp;nbsp;изменили.&lt;br /&gt;Здесь уже приходится искать узкие места. Первое&amp;nbsp;&amp;#8212; система написана на&amp;nbsp;PHP (OpenAds на&amp;nbsp;PHP4), второе&amp;nbsp;&amp;#8212; на&amp;nbsp;каждый клик выполняется &lt;b&gt;INSERT&lt;/b&gt;&amp;nbsp;запрос к&amp;nbsp;БД.&lt;br /&gt;Как вариант оптимизации&amp;nbsp;&amp;#8212; перевод системы на&amp;nbsp;FastCGI, но&amp;nbsp;на&amp;nbsp;долго&amp;nbsp;ли хватит этой оптимизации?&lt;br /&gt;В&amp;nbsp;итоге решили отказаться от&amp;nbsp;этой системы в&amp;nbsp;пользу собственной разработки.&lt;br /&gt;&lt;br /&gt;Сегодня на&amp;nbsp;сайте конференции разработчиков высоконагруженных систем highload++ [2] увидел презентацию архитектуры рекламной системы Mail.RU.&lt;br /&gt;&lt;br /&gt;&lt;img style="visibility:hidden;width:0px;height:0px;" border=0 width=0 height=0 src="http://counters.gigya.com/wildfire/IMP/CXNID=2000002.0NXC/bT*xJmx*PTEyNDcyMTI*OTQ4MTUmcHQ9MTI*NzIxNDkzMDE5MyZwPTEwMTkxJmQ9c3NfZW1iZWQmZz*yJnQ9Jm89NjM2MDYzYTVhMDA1NGJhYmI2MDQxNjgxMjA1ZGE*NmImb2Y9MA==.gif" /&gt;&lt;div style="width:425px;text-align:left" id="__ss_644415"&gt;&lt;a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/highload/2-rbmailru-presentation" title="!!2 Rb.Mail.Ru"&gt;!!2 Rb.Mail.Ru&lt;/a&gt;&lt;object style="margin:0px" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=2rbmailru-1223482704966431-8&amp;stripped_title=2-rbmailru-presentation" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=2rbmailru-1223482704966431-8&amp;stripped_title=2-rbmailru-presentation" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;"&gt;View more &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/highload"&gt;highload&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;Цифры говорят сами за&amp;nbsp;себя: 3&amp;nbsp;миллиарда показов в&amp;nbsp;сутки на&amp;nbsp;6&amp;nbsp;фронтендах и&amp;nbsp;3х&amp;nbsp;бекендах.&lt;br /&gt;&lt;br /&gt;_____&lt;br /&gt;1.&amp;nbsp;Официальный сайт OpenX&amp;nbsp;&amp;#8212; &lt;a href="http://www.openx.org/en/products"&gt;http://www.openx.org/en/products&lt;/a&gt;&lt;br /&gt;2.&amp;nbsp;Сайт конференции HighLoad++&amp;nbsp;&amp;#8212; &lt;a href="http://highload.ru"&gt;http://highload.ru&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;a href="http://incpp.blogspot.com/"&gt;In C++. Программирование на C++ и не только...&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8518171411908930166-1753059781991602627?l=incpp.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/InCpp/~4/SHMbF_k5fFs" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/InCpp/~3/SHMbF_k5fFs/blog-post.html</link><author>noreply@blogger.com (Андрей Булавинов)</author><thr:total>0</thr:total><feedburner:origLink>http://incpp.blogspot.com/2009/07/blog-post.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8518171411908930166.post-6666648794927128317</guid><pubDate>Fri, 03 Jul 2009 14:42:00 +0000</pubDate><atom:updated>2009-07-13T17:01:46.208+03:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">http</category><category domain="http://www.blogger.com/atom/ns#">сетевая разработка</category><category domain="http://www.blogger.com/atom/ns#">libevent</category><category domain="http://www.blogger.com/atom/ns#">протокол</category><category domain="http://www.blogger.com/atom/ns#">rpc</category><category domain="http://www.blogger.com/atom/ns#">ab</category><title>Разработка RPC приложений с использованием libevent</title><description>Разрабатывая клиент-серверные системы часто возникает вопрос, какой протокол выбрать.&lt;br /&gt;Этому вопросу следует уделить достаточно внимания, ведь протокол, новый или уже существующий,&lt;br /&gt;накладывает ряд ограничений и дополнительных трудозатрат на разработку и поддержку системы в будущем.&lt;br /&gt;&lt;br /&gt;При выборе протокола следует, как минимум, ответить на следующие вопросы:&lt;br /&gt;&amp;#151; как распределяются задачи между взаимодействующими узлами; Задачи для клиента, задачи для сервера;&lt;br /&gt;&amp;#151; какой объем данных будет минимальный для передачи, а какой максимальный;&lt;br /&gt;&amp;#151; как часто необходимо обмениваться данными;&lt;br /&gt;&amp;#151; какая топология узлов? Будут ли клиент и сервер находиться в одной подсети;&lt;br /&gt;&amp;#151; сколько потребуется времени/ресурсов для расширения протокола и сколько кода это может затронуть;&lt;br /&gt;&amp;#151; как предполагается организовывать защиту трафика;&lt;br /&gt;&amp;#151; критична ли скорость обмена данными и возможно ли масштабировать систему вертикально, например, за счет повышения пропускной способности канала.&lt;br /&gt;&lt;br /&gt;Я хотел бы поделиться опытом использования RPC протокола в системе с трехуровневой логической архитектурой.&lt;br /&gt;Решение использовать RPC с бинарным протоколом было следствием следующих факторов:&lt;br /&gt;&amp;#151; вся вычислительная нагрузка приходится на серверную часть (возможно горизонтальное масштабирование);&lt;br /&gt;&amp;#151; размер ответа небольшой, но сильно отличающийся для разных запросов;&lt;br /&gt;&amp;#151; обмениваться данными необходимо достаточно часто и с многих клиентов;&lt;br /&gt;&amp;#151; сервер будет находиться в одной гигабитной подсети с клиентами, поэтому размер пакета играет меньше роли чем время на установку нового соединения;&lt;br /&gt;&amp;#151; расширять функционал сервера прийдется неоднократно;&lt;br /&gt;&amp;#151; нет необходимости в защите трафика;&lt;br /&gt;&amp;#151; поскольку основная часть сервера написана на С, не хотелось путать туда тяжеловесные XML-RPC решения;&lt;br /&gt;&amp;#151; проверенный временем libevent предоставляет удобную и тонкую обвертку над процессом маршалинга и асинхронными вызовами.&lt;br /&gt;&lt;br /&gt;О технологии вызова удаленных процедур можно почитать например на citforum.ru [1], так что я не буду вдаваться в теорию, а покажу на примере, как использовать RPC в приложении на C/C++.&lt;br /&gt;Хочу добавить, что данное решение (libevent + RPC) является кроссплатформенным, проверял на FreeBSD, Mac OS X и Windows.&lt;br /&gt;&lt;br /&gt;Вот то, что нам необходимо для работы:&lt;br /&gt;1. Компилятор С/С++.&lt;br /&gt;2. Библиотека libevent (1.4.x/2.x).&lt;br /&gt;3. Python (необходим для скрипта event_rpcgen.py).&lt;br /&gt;4. Сам event_rpcgen.py (устанавливается в систему, либо можно взять из дистрибутива).&lt;br /&gt;&lt;br /&gt;Перед тем, как разрабатывать сервер и клиент, необходимо определиться с базовыми структурами запросов и ответов.&lt;br /&gt;В качестве примера я приведу сервер, который возвращает время с момента загрузки системы (uptime(1)) и информацию о системе (uname(1)), причем в ответе будет лишь та информация, которую запросит клиент.&lt;br /&gt;&lt;br /&gt;Что характерно для систем реализующих RPC, это процесс упорядочивания структур данных для передачи другому узлу, который может находиться как на локальной системе, так и на удаленной, таким образом, чтоб было возможно восстановить их в полной точности (сохраняя размеры и типы данных). Этот процесс называется маршалингом [2]. Практически любая библиотека реализующая RPC предоставляет средства автоматического маршалинга и демаршалинга. Не исключение и libevent.&lt;br /&gt;&lt;br /&gt;Создаем файл, в котором описываются структуры для запросов/ответов, расширение файла должно быть .rpc.&lt;br /&gt;&lt;br /&gt;Вот пример моего файла QueryTypes.rpc&lt;br /&gt;&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;struct StatRequest {&lt;br /&gt;   optional int uptime = 1;&lt;br /&gt;   optional int uname = 2;&lt;br /&gt;}&lt;br /&gt;struct StatReply {&lt;br /&gt;   optional string uptime = 1;&lt;br /&gt;   optional string uname = 2;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Доступны следующие типы данных:&lt;br /&gt;1. struct &amp;#151; структура, аналог struct в C (в конце точка с запятой не ставится).&lt;br /&gt;2. int &amp;#151; аналог uint32_t.&lt;br /&gt;3. string &amp;#151; char *, строка переменной длины.&lt;br /&gt;4. bytes &amp;#151; вектор uint8_t, можно указывать длину, например bytes data[24].&lt;br /&gt;5. array struct[type] &amp;#151; вектор структур type.&lt;br /&gt;&lt;br /&gt;Модификатор optional указывает на то, что это не обязательно поле, и его наличие необходимо проверять макросом EVTAG_HAS().&lt;br /&gt;&lt;br /&gt;После указания имени поля (поля именуются тегами) указывается его числовой id.&lt;br /&gt;&lt;br /&gt;Теперь можно генерировать код, для работы с этими структурами:&lt;br /&gt;&lt;pre class="bash" name="code"&gt;&lt;br /&gt;$ event_rpcgen.py QueryTypes.rpc&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Если все указано без ошибок, можно увидеть примерно следующее:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Reading "QueryTypes.rpc"&lt;br /&gt;  Created struct: StatRequest&lt;br /&gt;    Added entry: uptime&lt;br /&gt;    Added entry: uname&lt;br /&gt;  Created struct: StatReply&lt;br /&gt;    Added entry: uptime&lt;br /&gt;    Added entry: uname&lt;br /&gt;... creating "QueryTypes.gen.h"&lt;br /&gt;... creating "QueryTypes.gen.c"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;В результате, мы получили два файла, в котором реализованы все необходимые методы для работы с этими структурами, включая методы маршалинга и демаршалинга.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;RPC сервер&lt;/h2&gt;&lt;br /&gt;&lt;h3&gt;1. Заголовочные файлы&lt;/h3&gt;&lt;br /&gt;Нам понадобятся следующие заголовочные файлы:&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;#include &amp;lt;event.h&amp;gt;&lt;br /&gt;#include &amp;lt;evhttp.h&amp;gt;&lt;br /&gt;#include &amp;lt;evrpc.h&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;а так же заголовочный файл с нашими структурами. Тут есть один нюанс, необходимо включать его с модификатором "C":&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;#ifdef __cplusplus&lt;br /&gt;extern "C" {&lt;br /&gt;#endif&lt;br /&gt;&lt;br /&gt;#include "QueryTypes.gen.h"&lt;br /&gt;&lt;br /&gt;#ifdef __cplusplus&lt;br /&gt;}&lt;br /&gt;#endif&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;2. Регистрация удаленных процедур&lt;/h3&gt;&lt;br /&gt;Собственно то, ради чего была эта затея &amp;#151; процедуры для удаленного вызова. Их необходимо зарегистрировать и сгенерировать код для автоматизации рутинных вещей [2].&lt;br /&gt;Все вызовы RPC имеют следующий прототип: ИмяПроцедуры(СтруктураЗапроса, СтруктураОтвета).&lt;br /&gt;Я назвал процедуру GetServerStat:&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;// Регистрируем&lt;br /&gt;EVRPC_HEADER(GetServerStat, StatRequest, StatReply);&lt;br /&gt;// Генерируем автокод&lt;br /&gt;EVRPC_GENERATE(GetServerStat, StatRequest, StatReply);&lt;br /&gt;&lt;/pre&gt;Также, необходимо объявить функцию, которая будет обрабатывать вызов процедуры:&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;void GetServerStatCB(EVRPC_STRUCT(GetServerStat)* rpc, void * arg);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;3. Создание слушающего RPC сервера&lt;/h3&gt;&lt;br /&gt;Поскольку выбрана реализация на базе HTTP сервера, необходимо зарегистрировать сокет, и&lt;br /&gt;инициализировать HTTP мини-сервер. Создание сокета &amp;#151; дело тривиальное, это можно посмотреть&lt;br /&gt;в моем примере.&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;// Инициализируем базу механизма событий&lt;br /&gt;event_base * serv_base = event_init();&lt;br /&gt;// Создаем HTTP сервер (это, на самом деле, легковесная обвертка над сокетом)&lt;br /&gt;evhttp * http_base = evhttp_new(serv_base);&lt;br /&gt;// и указывем сокет, на каком он будет работать&lt;br /&gt;evhttp_accept_socket(http_base, server_sock);&lt;br /&gt;// Создаем базу для RPC протокола&lt;br /&gt;evrpc_base * rpc_base = evrpc_init(http_base);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;После этого, необходимо зарегистрировать все обработчики для всех удаленных процедур:&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;EVRPC_REGISTER(rpc_base, GetServerStat, StatRequest, StatReply, GetServerStatCB, NULL);&lt;/pre&gt;&lt;br /&gt;Все, можно запускать диспетчер событий, дальше работаем в обработчиках вызовов.&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;event_dispatch();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;При выходе, порядок очистки структур следующий:&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;EVRPC_UNREGISTER(rpc_base, GetServerStat);&lt;br /&gt;evrpc_free(rpc_base);  &lt;br /&gt;evhttp_free(http_base);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;4. Обработка запросов&lt;/h3&gt;&lt;br /&gt;Теперь самое интересное &amp;#151; обработка запросов и формирование ответов.&lt;br /&gt;В реализации обработчика выполняются нехитрые стандартные вещи:&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;void GetServerStatCB(EVRPC_STRUCT(GetServerStat)* rpc, void *arg)&lt;br /&gt;{&lt;br /&gt;    // Связывание запроса&lt;br /&gt;    StatRequest * request = rpc-&amp;gt;request;    &lt;br /&gt;    // и ответа&lt;br /&gt;    StatReply   * reply   = rpc-&amp;gt;reply;&lt;br /&gt;    // Проверка полей&lt;br /&gt;    if (EVTAG_HAS(request, uptime)) {&lt;br /&gt;        // и присвоение значений в ответной структуре&lt;br /&gt;        EVTAG_ASSIGN(reply, uptime, data.c_str());&lt;br /&gt;    }&lt;br /&gt;    // в конце обработчика, если все ОК, даем об этом знать&lt;br /&gt;    EVRPC_REQUEST_DONE(rpc);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Есть. А теперь клиент.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;RPC клиент&lt;/h2&gt;&lt;br /&gt;&lt;h3&gt;1. Заголовки&lt;/h3&gt;&lt;br /&gt;Заголовки подключаются такие же, как и в серверной части.&lt;br /&gt;&lt;h3&gt;2. Регистрация процедур&lt;/h3&gt;&lt;br /&gt;Процедуры регистрируем так же: &lt;b&gt;EVRPC_HEADER&lt;/b&gt; и &lt;b&gt;EVRPC_GENERATE&lt;/b&gt;&lt;br /&gt;А вот обработчик результата другой, а именно:&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;void GotServerStat(struct evrpc_status *status, struct StatRequest *request, struct StatReply *reply, void *arg);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;где&lt;br/&gt;&lt;br /&gt;&lt;b&gt;status&lt;/b&gt; &amp;#151; результат обработки удаленного вызова. Нас интересует случай &lt;b&gt;EVRPC_STATUS_ERR_NONE&lt;/b&gt; &amp;#151; значит все Ok,&lt;br /&gt;&lt;b&gt;request&lt;/b&gt; и &lt;b&gt;reply&lt;/b&gt; &amp;#151; наши структуры,&lt;br /&gt;&lt;b&gt;arg&lt;/b&gt; &amp;#151; произвольный аргумент (указывается при регистрации самого обработчика (см. далее).&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;3. Инициализация RPC&lt;/h3&gt;&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;// Событийная база&lt;br /&gt;event_base * base = event_init();&lt;br /&gt;// HTTP здесь нужен только для обработки заголовка HTTP пакета ( этот вызов лишь инициализирует внутренние буферы).&lt;br /&gt;evhttp     * http = evhttp_new(base);&lt;br /&gt;// Аналогично с RPC&lt;br /&gt;evrpc_base * rpc  = evrpc_init(http);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;А теперь, поехали: создаем подключение к RPC серверу&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;// IP адрес и порт сервера&lt;br /&gt;const char * host = "127.0.0.1";&lt;br /&gt;u_short      port = 8090;&lt;br /&gt;evhttp_connection * evcon = evhttp_connection_new(host, port);&lt;br /&gt;&lt;/pre&gt; &lt;br /&gt;Создаем пул подключений. Пул подключений &amp;#151; это такая структура, в которую можно добавить много разных подключений, и запросить у них наш запрос.&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;evrpc_pool * pool = evrpc_pool_new(base);&lt;br /&gt;// Добавляем подключение в пул&lt;br /&gt;evrpc_pool_add_connection(pool, evcon);&lt;br /&gt;// Создаем и инициализируем структуру запроса. Кстати, вызовы StatRequest_new, StatRequest_free,.. - генерируются&lt;br /&gt;// автоматически скриптом event_rpcgen.py&lt;br /&gt;StatRequest * stat_req = StatRequest_new();&lt;br /&gt;EVTAG_ASSIGN(stat_req, uptime, 1); // запрос на получение uptime (флаг 1)&lt;br /&gt;EVTAG_ASSIGN(stat_req, uname, 1);  // запрос на получение uname&lt;br /&gt;// Создаем структуру ответа&lt;br /&gt;StatReply * stat_rep = StatReply_new();&lt;br /&gt;// Делаем запрос, указав, что при получении ответа вызвать обработчик GotServerStat&lt;br /&gt;EVRPC_MAKE_REQUEST(GetServerStat, pool, stat_req, stat_rep, GotServerStat, NULL);&lt;br /&gt;// Обрабатываем запрос и ответ&lt;br /&gt;event_dispatch();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;В обработчике ответа вызовем функцию выхода из диспетчера, поэтому далее следует код очистки структур.&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;StatRequest_free(stat_req);&lt;br /&gt;StatReply_free(stat_rep);&lt;br /&gt;evrpc_pool_free(pool);&lt;br /&gt;evrpc_free(rpc);&lt;br /&gt;evhttp_free(http);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;4. Обработчик ответа&lt;/h3&gt;&lt;br /&gt;Обработчик ответа вызовется после получении ответа и демаршалинга структуры ответа.&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;void GotServerStat(struct evrpc_status *status, struct StatRequest *request, struct StatReply *reply, void *arg)&lt;br /&gt;{&lt;br /&gt;    // Проверяем статус возврата&lt;br /&gt;    if (status-&amp;gt;error == EVRPC_STATUS_ERR_NONE) {&lt;br /&gt;        // и читаем доступные значения&lt;br /&gt;        char * value = NULL;&lt;br /&gt;        if (EVTAG_HAS(reply, uptime) &amp;amp;&amp;amp; (EVTAG_GET(reply, uptime, &amp;amp;value) != -1)) {&lt;br /&gt;             printf("[Reply] uptime: %s\n", value);&lt;br /&gt;        }&lt;br /&gt;        if (EVTAG_HAS(reply, uname) &amp;amp;&amp;amp; (EVTAG_GET(reply, uname, &amp;amp;value) != -1)) {&lt;br /&gt;            printf("[Reply] uname: %s\n", value);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    // Можно выходить из цикла диспетчера событий&lt;br /&gt;    event_loopexit(NULL);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Как видно, здесь нет ничего сложного, внутренняя реализация этой технологии достаточно эффективна, о чем можно судить по результатам тестирования средствами Apachebench [3].&lt;br /&gt;&lt;pre class="bash" name="code"&gt;&lt;br /&gt;$ ab -c 100 -n 1000 -p post.http.txt -T application/octet-stream http://10.1.3.10:8080/.rpc.GetServerStat&lt;br /&gt;Server Hostname:        10.1.3.10&lt;br /&gt;Server Port:            8080&lt;br /&gt;&lt;br /&gt;Document Path:          /.rpc.GetServerStat&lt;br /&gt;Document Length:        136 bytes&lt;br /&gt;&lt;br /&gt;Concurrency Level:      100&lt;br /&gt;Time taken for tests:   0.067 seconds&lt;br /&gt;Complete requests:      1000&lt;br /&gt;Failed requests:        0&lt;br /&gt;Broken pipe errors:     0&lt;br /&gt;Non-2xx responses:      1058&lt;br /&gt;Total transferred:      283544 bytes&lt;br /&gt;Total POSTed:           250930&lt;br /&gt;HTML transferred:       143888 bytes&lt;br /&gt;Requests per second:    14925.37 [#/sec] (mean)&lt;br /&gt;Time per request:       6.70 [ms] (mean)&lt;br /&gt;Time per request:       0.07 [ms] (mean, across all concurrent requests)&lt;br /&gt;Transfer rate:          4232.00 [Kbytes/sec] received&lt;br /&gt;                        3745.22 kb/s sent&lt;br /&gt;                        7977.22 kb/s total&lt;br /&gt;&lt;br /&gt;Connnection Times (ms)&lt;br /&gt;              min  mean[+/-sd] median   max&lt;br /&gt;Connect:        0     1    0.4      1     4&lt;br /&gt;Processing:     3     4    0.8      4     8&lt;br /&gt;Waiting:        1     4    0.7      4     7&lt;br /&gt;Total:          3     6    0.9      6     9&lt;br /&gt;&lt;br /&gt;Percentage of the requests served within a certain time (ms)&lt;br /&gt;  50%      6&lt;br /&gt;  66%      6&lt;br /&gt;  75%      6&lt;br /&gt;  80%      7&lt;br /&gt;  90%      7&lt;br /&gt;  95%      8&lt;br /&gt;  98%      8&lt;br /&gt;  99%      9&lt;br /&gt; 100%      9 (last request)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Клиент и сервер находятся в одной сети, т.е. основное время тратится на соединение и обработку запросов.&lt;br /&gt;На этом, конечно же, все возможности RPC не заканчиваются, но для того, чтобы переступить не самый низкий порог входжения этого вполне достаточно.&lt;br /&gt;&lt;br /&gt;Скачать работающий пример RPC сервера и клинета (Makefile для UNIX/Max OS) можно &lt;a href="http://depositfiles.com/files/8yikk4lu5"&gt;отсюда&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Спасибо за внимание и успешной разработки.&lt;br /&gt;&lt;br /&gt;___&lt;br /&gt;1. Вызов удаленных процедур (RPC) &amp;#151; &lt;a href="http://www.citforum.ru/operating_systems/sos/glava_12.shtml"&gt;http://www.citforum.ru/operating_systems/sos/glava_12.shtml&lt;/a&gt;&lt;br /&gt;2. Теоретические основы маршалинга &amp;#151; &lt;a href="http://ru.wikipedia.org/wiki/%D0%9C%D0%B0%D1%80%D1%88%D0%B0%D0%BB%D0%B8%D0%BD%D0%B3"&gt;http://ru.wikipedia.org/wiki/Маршалинг&lt;/a&gt;&lt;br /&gt;3. Документация по работе с инструментом Apachebench &amp;#151; &lt;a href="http://httpd.apache.org/docs/2.2/programs/ab.html"&gt;http://httpd.apache.org/docs/2.2/programs/ab.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;a href="http://incpp.blogspot.com/"&gt;In C++. Программирование на C++ и не только...&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8518171411908930166-6666648794927128317?l=incpp.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/InCpp/~4/S_13lpRBsFU" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/InCpp/~3/S_13lpRBsFU/rpc-libevent.html</link><author>noreply@blogger.com (Андрей Булавинов)</author><thr:total>2</thr:total><feedburner:origLink>http://incpp.blogspot.com/2009/07/rpc-libevent.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8518171411908930166.post-774246475730325792</guid><pubDate>Wed, 20 May 2009 09:00:00 +0000</pubDate><atom:updated>2009-05-20T12:01:31.018+03:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">qnx</category><category domain="http://www.blogger.com/atom/ns#">вебинар</category><category domain="http://www.blogger.com/atom/ns#">ОСРВ</category><title>Вебинар от QNX SS "Exactly When Do You Need Realtime?"</title><description>&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;a href="http://3.bp.blogspot.com/_ym1v0B1Pi48/ShPGHEFl0yI/AAAAAAAACFQ/hpHknOyhTE4/s1600-h/qnx_logo.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img src="http://3.bp.blogspot.com/_ym1v0B1Pi48/ShPGHEFl0yI/AAAAAAAACFQ/hpHknOyhTE4/s320/qnx_logo.gif" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;21 мая, компания &lt;a href="http://www.qnx.com/"&gt;QNX Software Systems&lt;/a&gt; &lt;a href="http://www.qnx.com/news/web_seminars/exactly-when-do-you-need-realtime.html"&gt;проведет&lt;/a&gt; бесплатный онлайн-семинар, который должен помочь при выборе операционной системы для встраиваемых систем.&lt;br /&gt;&lt;br /&gt;Продолжительность:&lt;b&gt; &lt;/b&gt; 1 час, включая вопросы.&lt;br /&gt;&lt;br /&gt;Все ли встраиваемые проекты нуждаются в ОСРВ?.. Завтра узнаем.&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;a href="http://incpp.blogspot.com/"&gt;In C++. Программирование на C++ и не только...&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8518171411908930166-774246475730325792?l=incpp.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/InCpp/~4/_XKDI_Oh_EE" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/InCpp/~3/_XKDI_Oh_EE/qnx-ss-exactly-when-do-you-need.html</link><author>noreply@blogger.com (Андрей Булавинов)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_ym1v0B1Pi48/ShPGHEFl0yI/AAAAAAAACFQ/hpHknOyhTE4/s72-c/qnx_logo.gif" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://incpp.blogspot.com/2009/05/qnx-ss-exactly-when-do-you-need.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8518171411908930166.post-336163135539958977</guid><pubDate>Fri, 08 May 2009 09:49:00 +0000</pubDate><atom:updated>2009-05-08T12:49:01.156+03:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">код</category><category domain="http://www.blogger.com/atom/ns#">документация</category><category domain="http://www.blogger.com/atom/ns#">чтение кода</category><title>К проекту прилагается отличная документация в формате С</title><description>Отличная статья про то, как хорошо и полезно уметь читать и читать исходный код:&lt;br /&gt;
&lt;a href="http://gaperton.livejournal.com/32772.html"&gt;http://gaperton.livejournal.com/32772.html&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Когда я только начинал программировать, у меня совсем не было интернета, а в моем городе не было вменяемой литературы, поэтому я привык пользоваться справкой. &lt;br /&gt;
Читая сопроводительные тексты к среде разработки и к библиотекам, наткнулся на следующее высказывание: "Чтобы научиться программировать – нужно читать очень много кода, а писать еще больше".&lt;br /&gt;
&lt;br /&gt;
Документация-документацией, но все же, не помешает (а часто и поможет) знание того, как это работает "под капотом".&lt;div class="blogger-post-footer"&gt;&lt;a href="http://incpp.blogspot.com/"&gt;In C++. Программирование на C++ и не только...&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8518171411908930166-336163135539958977?l=incpp.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/InCpp/~4/i1gLewU1Btc" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/InCpp/~3/i1gLewU1Btc/blog-post.html</link><author>noreply@blogger.com (Андрей Булавинов)</author><thr:total>0</thr:total><feedburner:origLink>http://incpp.blogspot.com/2009/05/blog-post.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8518171411908930166.post-5660180949073736880</guid><pubDate>Thu, 07 May 2009 08:28:00 +0000</pubDate><atom:updated>2010-05-03T17:18:23.557+03:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">http</category><category domain="http://www.blogger.com/atom/ns#">libevent</category><category domain="http://www.blogger.com/atom/ns#">сервер</category><title>Написание своего HTTP сервера с использованием libevent</title><description>Библиотека libevent содержит в себе простейший асинхронный HTTP сервер, который можно&lt;br /&gt;
без особого труда встроить в собственное приложение для обслуживания HTTP запросов.&lt;br /&gt;
&lt;br /&gt;
Для использования этой возможности достаточно добавить в код следующее:&lt;br /&gt;
&lt;br /&gt;
1. Подключить заголовочный файл &amp;lt;evhttp.h&amp;gt;:&lt;br /&gt;
&lt;pre class="cpp" name="code"&gt;#include &amp;lt;evhttp.h&amp;gt;
&lt;/pre&gt;&lt;br /&gt;
2. Инициализировать базу событийного движка:&lt;br /&gt;
&lt;pre class="cpp" name="code"&gt;event_base * serv_base = (event_base *)event_init();
&lt;/pre&gt;&lt;br /&gt;
3. Инициализировать HTTP сервер:&lt;br /&gt;
&lt;pre class="cpp" name="code"&gt;evhttp * http_server = evhttp_new(serv_base);
&lt;/pre&gt;&lt;br /&gt;
4. Указать, на каком сокете слушать подключения:&lt;br /&gt;
&lt;pre class="cpp" name="code"&gt;evhttp_accept_socket(http_server, server_sock);
&lt;/pre&gt;&lt;br /&gt;
5. Выставить callback'и на запросы. Можно добавлять на каждый URI свой обработчик:&lt;br /&gt;
&lt;pre class="cpp" name="code"&gt;evhttp_set_cb(http_server, "/news", on_request_news, NULL);
&lt;/pre&gt;&lt;br /&gt;
6. Выставить обработчик на остальные запросы:&lt;br /&gt;
&lt;pre class="cpp" name="code"&gt;evhttp_set_gencb(http_server, on_request, NULL);
&lt;/pre&gt;&lt;br /&gt;
7. Запустить цикл обработки запросов:&lt;br /&gt;
&lt;pre class="cpp" name="code"&gt;event_base_dispatch(serv_base);
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
Реализация HTTP сервера является потоко-безопасной (thread safe).&lt;br /&gt;
&lt;br /&gt;
Есть еще один нюанс: настоятельно рекомендуется игнорировать сигнал SIGPIPE.&lt;br /&gt;
Делается это следующим вызовом:&lt;br /&gt;
&lt;pre class="cpp" name="code"&gt;signal(SIGPIPE, SIG_IGN);
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
Описание всех функция для работы с HTTP протоколом&lt;br /&gt;
можно найти в &lt;a href="http://monkey.org/%7Eprovos/libevent/doxygen-1.4.10/evhttp_8h.html"&gt;документации&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Вот работающий пример простого HTTP сервера, который на все запросы отдает динамическую&lt;br /&gt;
страничку с некоторой информацией о клиенте.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="cpp" name="code"&gt;/*
* \file: http_server.cpp
* \description: Simple HTTP server
*
*/
#include &amp;lt;errno.h&amp;gt;
#include &amp;lt;event.h&amp;gt;
#include &amp;lt;evhttp.h&amp;gt;
#include &amp;lt;sys/socket.h&amp;gt;
#include &amp;lt;sys/types.h&amp;gt;
#include &amp;lt;signal.h&amp;gt;

#include &amp;lt;netinet/in.h&amp;gt;
#include &amp;lt;arpa/inet.h&amp;gt;

#include &amp;lt;iostream&amp;gt;

const short  SERVER_BACKLOG    = 128;
const short  BUF_LEN           = 26;
const char   RESPONCE[BUF_LEN] = "&amp;lt;H1&amp;gt;Hello there&amp;lt;/H1&amp;gt;&amp;lt;BR/&amp;gt;";
const char * SERVER_NAME       = "Simple HTTP Server";

void on_request(struct evhttp_request *, void *);

int main(int argc, char **argv)
{
if (argc &amp;lt; 3) {
std::cout &amp;lt;&amp;lt; "Start as:" &amp;lt;&amp;lt; std::endl 
&amp;lt;&amp;lt; argv[0] &amp;lt;&amp;lt; " host_address port" &amp;lt;&amp;lt; std::endl;
return 1;
}

int server_sock = socket(AF_INET, SOCK_STREAM, 0);
if (server_sock == -1) {
std::cout &amp;lt;&amp;lt; "Error socket(): " &amp;lt;&amp;lt; strerror(errno) &amp;lt;&amp;lt; std::endl;
return 1;
}

u_short      port  = atol(argv[2]);
const char * host  = argv[1];
sockaddr_in  sa;
int          on    = 1;
sa.sin_family      = AF_INET;
sa.sin_port        = htons(port);
sa.sin_addr.s_addr = inet_addr(host);

if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &amp;amp;on, sizeof(on)) == -1) {
std::cout &amp;lt;&amp;lt; "Error setsockopt(): " &amp;lt;&amp;lt; strerror(errno) &amp;lt;&amp;lt; std::endl;
return 1;
}

// Bind server socket to ip:port
if (bind(server_sock, (const sockaddr*)&amp;amp;sa, sizeof(sa)) == -1) {
std::cout &amp;lt;&amp;lt; "Error bind(): " &amp;lt;&amp;lt; strerror(errno) &amp;lt;&amp;lt; " on: " &amp;lt;&amp;lt; host &amp;lt;&amp;lt; ":" &amp;lt;&amp;lt; port &amp;lt;&amp;lt; std::endl;
return 1;
}
// Make server to listen
if (listen(server_sock, SERVER_BACKLOG) == -1) {
std::cout &amp;lt;&amp;lt; "Error listen(): " &amp;lt;&amp;lt; strerror(errno) &amp;lt;&amp;lt; std::endl;
return 1;
}
// Init events
event_base * serv_base   = (event_base *)event_init();
evhttp     * http_server = evhttp_new(serv_base);

// Ignore SIGPIPE
signal(SIGPIPE, SIG_IGN);

if (evhttp_accept_socket(http_server, server_sock) == -1) {
std::cout &amp;lt;&amp;lt; "Error evhttp_accept_socket(): " &amp;lt;&amp;lt; strerror(errno) &amp;lt;&amp;lt; std::endl;
return 1;
}
// Set HTTP request callback                               
evhttp_set_gencb(http_server, on_request, NULL);
// Dispatch events
event_base_dispatch(serv_base);

return 0;
}

void on_request(struct evhttp_request * req, void * arg)
{
// Create responce buffer
struct evbuffer *evb = evbuffer_new();
if (!evb) { return; }

// Add heading text
evbuffer_add_printf(evb, "&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;%s Page&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY&amp;gt;\n", SERVER_NAME);
// Add buffer
evbuffer_add(evb, RESPONCE, BUF_LEN);
// Add formatted text
evbuffer_add_printf(evb, "Your request is &amp;lt;B&amp;gt;%s&amp;lt;/B&amp;gt; from &amp;lt;B&amp;gt;%s&amp;lt;/B&amp;gt;.&amp;lt;BR/&amp;gt;Your user agent is '%s'\n", 
req-&amp;gt;uri, req-&amp;gt;remote_host, evhttp_find_header(req-&amp;gt;input_headers, "User-Agent"));
// Add footer
evbuffer_add_printf(evb, "&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;");

// Set HTTP headers
evhttp_add_header(req-&amp;gt;output_headers, "Server", SERVER_NAME);
evhttp_add_header(req-&amp;gt;output_headers, "Connection", "close");

// Send reply
evhttp_send_reply(req, HTTP_OK, "OK", evb);

// Free memory
evbuffer_free(evb);
}
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
Makefile для сборки:&lt;br /&gt;
&lt;pre class="Bash" name="code"&gt;SRCS=http_server.cpp
LDFLAGS=-levent
CXXFLAGS=-I/usr/local/include -L/usr/local/lib
PROG=http_server

all:
c++ ${SRCS} -o ${PROG} ${LDFLAGS} ${CXXFLAGS}

clean:
rm -f ${PROG}
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
А вот результаты тестирования Apache Benchmark:&lt;br /&gt;
&lt;pre&gt;ab -c 100 -n 1000 "http://192.168.1.110:10000/test"

Server Software:        SimpleHTTPServer
Server Hostname:        192.168.1.110
Server Port:            10000

Document Path:          /test
Document Length:        199 bytes

Concurrency Level:      100
Time taken for tests:   0.185 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      308000 bytes
HTML transferred:       199000 bytes
Requests per second:    5393.74 [#/sec] (mean)
Time per request:       18.540 [ms] (mean)
Time per request:       0.185 [ms] (mean, across all concurrent requests)
Transfer rate:          1622.34 [Kbytes/sec] received

Connection Times (ms)
min  mean[+/-sd] median   max
Connect:        0    5   2.8      5      16
Processing:     5   13   3.9     13      23
Waiting:        2   10   3.9      9      22
Total:         11   18   3.4     18      27

Percentage of the requests served within a certain time (ms)
50%     18
66%     19
75%     20
80%     21
90%     22
95%     24
98%     25
99%     26
100%     27 (longest request)
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
Сервер был запущен локально на моем ноутбуке, на сервере результаты конечно же получше.&lt;br /&gt;
Но для сотни параллельных запросов – это неплохо.&lt;div class="blogger-post-footer"&gt;&lt;a href="http://incpp.blogspot.com/"&gt;In C++. Программирование на C++ и не только...&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8518171411908930166-5660180949073736880?l=incpp.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/InCpp/~4/C3xnFMKUw9E" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/InCpp/~3/C3xnFMKUw9E/http-libevent.html</link><author>noreply@blogger.com (Андрей Булавинов)</author><thr:total>5</thr:total><feedburner:origLink>http://incpp.blogspot.com/2009/05/http-libevent.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8518171411908930166.post-5600358919826728966</guid><pubDate>Mon, 27 Apr 2009 15:10:00 +0000</pubDate><atom:updated>2009-04-27T18:10:51.067+03:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">thread-safe</category><category domain="http://www.blogger.com/atom/ns#">libevent</category><category domain="http://www.blogger.com/atom/ns#">обновление</category><title>Обновление библиотеки libevent</title><description>17 апреля вышла новая версия libevent 2.0, в которой существенно переработано и улучшено API для &lt;br /&gt;
работы с асинхронными событиями.&lt;br /&gt;
&lt;br /&gt;
Судя по тому, что указано на официальном сайте, практически весь код, который работал &lt;br /&gt;
на версии 1.4, будет работать на libevent 2.0, но настоятельно рекомендуется для нового кода&lt;br /&gt;
использовать новую версию библиотеки. Так же необходимо перелинковать старые приложения.&lt;br /&gt;
&lt;br /&gt;
Что изменилось:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;стала более удобной структура заголовочных файлов;&lt;/li&gt;
&lt;li&gt;улучшился потоко-безопасный API&lt;/li&gt;
&lt;li&gt;появились перекрываемые функции работающие с памятью;&lt;/li&gt;
&lt;li&gt;создание event_base стало конфигурируемое: в рантайме можно выбирать любой из доступных бекендов;&lt;/li&gt;
&lt;li&gt;сокеты стали абстрактным типом: теперь нет необходимости приводить дескрипторы к int;&lt;/li&gt;
&lt;li&gt;стало возможным выставлять таймауты для постоянных событий (раньше это не имело смысла);&lt;/li&gt;
&lt;li&gt;теперь возможно выставлять множество одинаковых событий на один дескриптор;&lt;/li&gt;
&lt;li&gt;многие вещи стали действительно thread-safe&lt;/li&gt;
&lt;li&gt;появилась поддержка edge-triggered событий (если поддерживается бекендом);&lt;/li&gt;
&lt;li&gt;улучшения в evbuffers (множество исправлений в работе с памятью);&lt;/li&gt;
&lt;li&gt;переработан механизм работы с внутренней памятью (раньше это были цельные блоки,которые приходилось двигать и изменять в размере, что не есть хорошо. Теперь это связный список страниц);&amp;nbsp;&lt;/li&gt;
&lt;li&gt;более гибкий механизм чтения из буфера&lt;/li&gt;
&lt;li&gt;поддержка zero-copy в буферах evbuffers;&lt;/li&gt;
&lt;li&gt;множественные колбеки на один буфер evbuffer;&lt;/li&gt;
&lt;li&gt;новый интерфейс колбеков;&lt;/li&gt;
&lt;li&gt;фильтрация буферизированного ввода-вывода;&lt;/li&gt;
&lt;li&gt;и много чего другого.&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;a href="http://incpp.blogspot.com/"&gt;In C++. Программирование на C++ и не только...&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8518171411908930166-5600358919826728966?l=incpp.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/InCpp/~4/Lupqgs1Yd34" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/InCpp/~3/Lupqgs1Yd34/libevent_27.html</link><author>noreply@blogger.com (Андрей Булавинов)</author><thr:total>2</thr:total><feedburner:origLink>http://incpp.blogspot.com/2009/04/libevent_27.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8518171411908930166.post-1069134138775772149</guid><pubDate>Thu, 23 Apr 2009 09:33:00 +0000</pubDate><atom:updated>2009-04-23T12:48:54.155+03:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">databases</category><category domain="http://www.blogger.com/atom/ns#">libpqxx</category><category domain="http://www.blogger.com/atom/ns#">postgresql</category><category domain="http://www.blogger.com/atom/ns#">data access</category><title>Работа с PostgreSQL. Использование libpqxx</title><description>Существует, как минимум, два официальных клиентских C++ API для работы с PostgreSQL:&lt;br /&gt;libpq++ [1] и libpqxx [2]. Обе библиотеки распространяются свободно, с открытым&lt;br /&gt;исходным кодом и хорошо документированы.&lt;br /&gt;Для себя я выбрал libpqxx: являясь очень гибкой, она остается так же достаточно простой в использовании.&lt;br /&gt;&lt;br /&gt;Хотя, наверное, это и не самая простая библиотека, но однообразный интерфейс к данным&lt;br /&gt;и привычные для C++ разработчика итераторы вместо "get_next_row" для доступа к результатам&lt;br /&gt;запроса, делают ее использование интуитивно понятным. Так же поддерживаются потоки,&lt;br /&gt;где это имеет смысл, а поля могут быть считаны в переменные шаблонными методами.&lt;br /&gt;В общем, все, как в нормальных C++ библиотеках.&lt;br /&gt;&lt;br /&gt;Вот несколько причин, по которым можно выбрать именно libpqxx:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Согласованность с языком&lt;/span&gt;. В разумной мере используются фичи современного&lt;br /&gt;C++ такие, как шаблоны (templates), исключения (exceptions), различного типы итераторов.&lt;br /&gt;В библиотеке, по возможности, используются стандартные вещи из STL.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Структура&lt;/span&gt;, позволяющая писать "хороший" код. Многие проблемы обнаруживаются&lt;br /&gt;на этапе компиляции или тестирования, а не во время работы.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Мощность&lt;/span&gt;. Такие встроенные фичи, как автоматическое восстановление соединения и&lt;br /&gt;управление транзакциями освобождают разработчика от низкоуровневой рутинной работы.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Гибкость&lt;/span&gt;. С учетом описанного выше, можно сделать вывод, что это не фреймворк.&lt;br /&gt;Ничто не заставляет втискивать свой код в чужие обработчики. В ней нет доморощенных&lt;br /&gt;строк и классов исключений. Код библиотеки живет в своем пространстве имен (pqxx)&lt;br /&gt;и полностью прячет нативный C API.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;Остальные достопримечательности библиотеки можно почитать на официальном сайте [2].&lt;br /&gt;&lt;br /&gt;Итак, что же необходимо для работы?&lt;br /&gt;&lt;br /&gt;Во-первых, необходима нативная libpq.so/libpq.dll.&lt;br /&gt;Во-вторых, сама libpqxx.so/libpqxx.dll.&lt;br /&gt;&lt;br /&gt;Что касается подхода к работе с базой данных, тут стоит обратить внимание, что&lt;br /&gt;доступ к базе данных выполняются через объект транзакции pqxx::transaction.&lt;br /&gt;Поэтому, знание интерфейсов этих классов является фундаментальным [3].&lt;br /&gt;&lt;br /&gt;Для работы с libpqxx™ нам необходимо, как минимум следующие классы:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;pqxx::connection&lt;/span&gt; – представляет собой обвертку к соединению в программе к back-end'у PostgreSQL™.&lt;br /&gt;Можно открывать множество соединений ко многим базам данных.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;pqxx::work&lt;/span&gt; – тип для шаблона pqxx::transaction, представляющий собой саму транзакцию,&lt;br /&gt;которая выполняется в контексте подключения (pqxx::connection). Если произойдет&lt;br /&gt;какая-нибудь проблема в рамках этой транзакции – выполнится полный ее откат к исходному&lt;br /&gt;состоянию.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;pqxx::result&lt;/span&gt; – контейнер, содержащий результат работы запроса или команды выполненных&lt;br /&gt;в транзакции.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;В качестве примера, приведу программу, которая выполняет запрос и выводит результат&lt;br /&gt;на экран в виде field='value'.&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;#include &amp;lt;pqxx/connection&amp;gt;&lt;br /&gt;#include &amp;lt;pqxx/transaction&amp;gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;string&amp;gt;&lt;br /&gt;#include &amp;lt;sstream&amp;gt;&lt;br /&gt;&lt;br /&gt;void help()&lt;br /&gt;{&lt;br /&gt;   std::cout &amp;lt;&amp;lt; "Usage: &amp;lt;host&amp;gt; &amp;lt;user&amp;gt; &amp;lt;password&amp;gt; &amp;lt;database&amp;gt;" &amp;lt;&amp;lt; std::endl;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main(int argc, char **argv)&lt;br /&gt;{&lt;br /&gt;   // Check arguments&lt;br /&gt;   if (argc &amp;lt; 5) {&lt;br /&gt;       help();&lt;br /&gt;       return 1;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   // Prepare connection string&lt;br /&gt;   std::ostringstream conn_string("");&lt;br /&gt;   conn_string &amp;lt;&amp;lt; "host=" &amp;lt;&amp;lt; argv[1]&lt;br /&gt;       &amp;lt;&amp;lt; " user=" &amp;lt;&amp;lt; argv[2]&lt;br /&gt;       &amp;lt;&amp;lt; " password=" &amp;lt;&amp;lt; argv[3]&lt;br /&gt;       &amp;lt;&amp;lt; " dbname=" &amp;lt;&amp;lt; argv[4];&lt;br /&gt;&lt;br /&gt;   do {&lt;br /&gt;       // Create connection&lt;br /&gt;       try {&lt;br /&gt;           pqxx::connection conn(conn_string.str());&lt;br /&gt;           pqxx::work       xact(conn, "SampleSelect");&lt;br /&gt;&lt;br /&gt;           std::string      query("SELECT * from news limit 10");&lt;br /&gt;           // Execute query&lt;br /&gt;           try {&lt;br /&gt;               pqxx::result res = xact.exec(query);&lt;br /&gt;               if (!res.size()) {&lt;br /&gt;                   std::cout &amp;lt;&amp;lt; "Empty result set." &amp;lt;&amp;lt; std::endl;&lt;br /&gt;                   break;&lt;br /&gt;               }&lt;br /&gt;               // Show results&lt;br /&gt;               for (pqxx::result::const_iterator i = res.begin(), r_end = res.end(); i != r_end; ++i) {&lt;br /&gt;                   // Iterate fields&lt;br /&gt;                   for (pqxx::result::const_fielditerator f = i-&amp;gt;begin(), f_end = i-&amp;gt;end(); f != f_end; ++f) {&lt;br /&gt;                       std::cout &amp;lt;&amp;lt; f-&amp;gt;name() &amp;lt;&amp;lt; " = '" &amp;lt;&amp;lt; f-&amp;gt;c_str() &amp;lt;&amp;lt; "'" &amp;lt;&amp;lt; std::endl;&lt;br /&gt;                   }&lt;br /&gt;                   std::cout &amp;lt;&amp;lt; std::endl;&lt;br /&gt;               }&lt;br /&gt;           } catch (...) {&lt;br /&gt;               std::cout &amp;lt;&amp;lt; "Failed to execute query: " &amp;lt;&amp;lt; query &amp;lt;&amp;lt; std::endl;&lt;br /&gt;               break;&lt;br /&gt;           }&lt;br /&gt;       } catch (pqxx::broken_connection) {&lt;br /&gt;           std::cout &amp;lt;&amp;lt; "Failed to establish connection." &amp;lt;&amp;lt; std::endl;&lt;br /&gt;           break;&lt;br /&gt;       }&lt;br /&gt;       std::cout &amp;lt;&amp;lt; "Query successfully executed." &amp;lt;&amp;lt; std::endl;&lt;br /&gt;&lt;br /&gt;       return 0;&lt;br /&gt;   } while (false);&lt;br /&gt;&lt;br /&gt;   return 1;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Makefile выглядит следующим образом:&lt;br /&gt;&lt;pre class="bash" name="code"&gt;&lt;br /&gt;SRC=pqxx_sample.cpp&lt;br /&gt;PROG=pqxx_sample&lt;br /&gt;&lt;br /&gt;all:&lt;br /&gt; c++ ${SRC} -o ${PROG} `pkg-config --libs --cflags libpqxx`&lt;br /&gt;clean:&lt;br /&gt; rm -f *.o ${PROG}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Как видно из примера, строкой подключения является стандартное перечисление ключ-значение,&lt;br /&gt;которое можно собрать, например, в &lt;span style="font-weight: bold;"&gt;std::ostringstream&lt;/span&gt; [4].&lt;br /&gt;&lt;br /&gt;Далее, подключение заворачивается в &lt;span style="font-weight: bold;"&gt;try-catch(pqxx::broken_connection)&lt;/span&gt;.&lt;br /&gt;После выполнения запроса выполняется двойной цикл: первый по записям, второй по полям.&lt;br /&gt;&lt;br /&gt;Конструкция &lt;span style="font-weight: bold;"&gt;do {} while (false)&lt;/span&gt; здесь используется для уменьшения цикломатической сложности.&lt;br /&gt;&lt;br /&gt;На этом возможности библиотеки libpqxx, естественно, не заканчиваются. О них можно&lt;br /&gt;почитать в справочнике [3].&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;libpq++ – &lt;a href="http://www.postgresql.org/docs/7.2/static/libpqplusplus.html"&gt;http://www.postgresql.org/docs/7.2/static/libpqplusplus.html&lt;/a&gt;&lt;/li&gt;&lt;li&gt;libpqxx – &lt;a href="http://pqxx.org/development/libpqxx/"&gt;http://pqxx.org/development/libpqxx/&lt;/a&gt; &lt;/li&gt;&lt;li&gt;Справочная информация – &lt;a href="http://pqxx.org/devprojects/libpqxx/doc/3.0/html/Reference/"&gt;http://pqxx.org/devprojects/libpqxx/doc/3.0/html/Reference/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;std::ostringstream – &lt;a href="http://www.cplusplus.com/reference/iostream/ostringstream/"&gt;http://www.cplusplus.com/reference/iostream/ostringstream/&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;a href="http://incpp.blogspot.com/"&gt;In C++. Программирование на C++ и не только...&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8518171411908930166-1069134138775772149?l=incpp.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/InCpp/~4/QMoZxrkqWJo" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/InCpp/~3/QMoZxrkqWJo/postgresql-libpqxx.html</link><author>noreply@blogger.com (Андрей Булавинов)</author><thr:total>5</thr:total><feedburner:origLink>http://incpp.blogspot.com/2009/04/postgresql-libpqxx.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8518171411908930166.post-8016754255822023659</guid><pubDate>Wed, 08 Apr 2009 09:50:00 +0000</pubDate><atom:updated>2009-04-08T12:50:45.861+03:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">http</category><category domain="http://www.blogger.com/atom/ns#">API</category><category domain="http://www.blogger.com/atom/ns#">сетевая разработка</category><category domain="http://www.blogger.com/atom/ns#">callback</category><category domain="http://www.blogger.com/atom/ns#">эхо-сервер</category><category domain="http://www.blogger.com/atom/ns#">libevent</category><category domain="http://www.blogger.com/atom/ns#">асинхронный ввод/вывод</category><title>Использование libevent в сетевых приложениях</title><description>API библиотеки &lt;a href="http://www.monkey.org/%7Eprovos/libevent/"&gt;libevent&lt;/a&gt; предоставляет удобный механизм callback-функций на появление соответствующего события, связанного с файловым дескриптором или по истечению таймаута, а также callback'и на сигналы или обычные временные интервалы.&lt;br /&gt;
&lt;br /&gt;
На текущий момент, libevent поддерживает механизмы /dev/poll, kqueue, event ports, select, poll, epoll. За счет прозрачного API библиотека может развиваться без необходимости менять что-либо в приложениях, которые используют libevent. Как результат, libevent позволяет разрабатывать кроссплатформенные приложения и использовать наиболее подходящий механизм событий в конкретной операционной системе. &lt;br /&gt;
Так же, libevent можно использовать в многопоточных приложениях.&lt;br /&gt;
libevent работает на Linux, *BSD, Max OS X, Solaris и Windows.&lt;br /&gt;
&lt;br /&gt;
К примеру, libevent используют такие системы, как &lt;a href="http://www.danga.com/memcached"&gt;Memcached&lt;/a&gt; – высокопроизводительная   распределенная система кэширования, &lt;a href="http://www.torproject.org/"&gt;Tor&lt;/a&gt; – анонимайзер, &lt;a href="http://www.citi.umich.edu/u/provos/systrace/"&gt;Systrace&lt;/a&gt; – песочница для системных вызовов.&lt;br /&gt;
&lt;br /&gt;
Использовать в своем проекте libevent достаточно просто:&lt;br /&gt;
Включить заголовочный файл:&lt;br /&gt;
&lt;pre class="cpp" name="code"&gt;#include &lt;event.h&gt;
&lt;/event.h&gt;&lt;/pre&gt;и указать линковщику флаг -levent.&lt;br /&gt;
Перед использованием функций из этой библиотеки, необходимо выполнить инициализацию вызовом функции &lt;br /&gt;
&lt;pre class="cpp" name="code"&gt;event_init()
&lt;/pre&gt;После этого можно регистрировать callback'и на любые дескрипторы или таймауты.&lt;br /&gt;
Вот пример простейшего сетевого эхо-сервера:&lt;br /&gt;
&lt;pre class="cpp" name="code"&gt;#include &amp;lt;event.h&amp;gt;
#include &amp;lt;sys/socket.h&amp;gt;
#include &amp;lt;sys/types.h&amp;gt;
#include &amp;lt;netinet/in.h&amp;gt;
#include &amp;lt;arpa/inet.h&amp;gt;

#include &amp;lt;iostream&amp;gt;

// Read/write buffer max length
static const size_t MAX_BUF = 512;

typedef struct {
    struct event ev;
    char         buf[MAX_BUF];
    size_t       offset;
    size_t       size;
} ConnectionData;

void on_connect(int fd, short event, void *arg);
void client_read(int fd, short event, void *arg);
void client_write(int fd, short event, void *arg);

int main(int argc, char **argv)
{
    // Check arguments
    if (argc &amp;lt; 3) {
        std::cout &amp;lt;&amp;lt; "Run with options: &amp;lt;ip address&amp;gt; &amp;lt;port&amp;gt;" &amp;lt;&amp;lt; std::endl;
        return 1;
    }
    // Create server socket
    int server_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (server_sock == -1) {
        std::cerr &amp;lt;&amp;lt; "Failed to create socket" &amp;lt;&amp;lt; std::endl;
        return 1;
    }

    sockaddr_in sa;
    int         on      = 1;
    char      * ip_addr = argv[1];
    short       port    = atoi(argv[2]);
 
    sa.sin_family       = AF_INET;
    sa.sin_port         = htons(port);
    sa.sin_addr.s_addr  = inet_addr(ip_addr);

    // Set option SO_REUSEADDR to reuse same host:port in a short time
    if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &amp;amp;on, sizeof(on)) == -1) {
        std::cerr &amp;lt;&amp;lt; "Failed to set option SO_REUSEADDR" &amp;lt;&amp;lt; std::endl;
        return 1;
    }

    // Bind server socket to ip:port
    if (bind(server_sock, reinterpret_cast&amp;lt;const sockaddr*&amp;gt;(&amp;amp;sa), sizeof(sa)) == -1) {
        std::cerr &amp;lt;&amp;lt; "Failed to bind server socket" &amp;lt;&amp;lt; std::endl;
        return 1;
    }

    // Make server to listen
    if (listen(server_sock, 10) == -1) {
        std::cerr &amp;lt;&amp;lt; "Failed to make server listen" &amp;lt;&amp;lt; std::endl;
        return 1;
    }
 
    // Init events
    struct event evserver_sock;
    // Initialize
    event_init();
    // Set connection callback (on_connect()) to read event on server socket
    event_set(&amp;amp;evserver_sock, server_sock, EV_READ, on_connect, &amp;amp;evserver_sock);
    // Add server event without timeout
    event_add(&amp;amp;evserver_sock, NULL);

    // Dispatch events
    event_dispatch();

    return 0;
}

// Handle new connection {{{
void on_connect(int fd, short event, void *arg) 
{
    sockaddr_in client_addr;
    socklen_t   len = 0;

    // Accept incoming connection
    int sock = accept(fd, reinterpret_cast&amp;lt;sockaddr*&amp;gt;(&amp;amp;client_addr), &amp;amp;len);
    if (sock &amp;lt; 1) { 
        return; 
    }
 
    // Set read callback to client socket
    ConnectionData * data = new ConnectionData;
    event_set(&amp;amp;data-&amp;gt;ev, sock, EV_READ, client_read, data);
    // Reschedule server event
    event_add(reinterpret_cast&amp;lt;struct event*&amp;gt;(arg), NULL);
    // Schedule client event
    event_add(&amp;amp;data-&amp;gt;ev, NULL);
}
//}}}

// Handle client request {{{
void client_read(int fd, short event, void *arg)
{
    ConnectionData * data = reinterpret_cast&amp;lt;ConnectionData*&amp;gt;(arg);
    if (!data) {
        close(fd);
        return;
    }
    int len = read(fd, data-&amp;gt;buf, MAX_BUF - 1);
    if (len &amp;lt; 1) {
        close(fd);
        delete data;
        return;
    }
    data-&amp;gt;buf[len] = 0;
    data-&amp;gt;size     = len;
    data-&amp;gt;offset   = 0;
    // Set write callback to client socket
    event_set(&amp;amp;data-&amp;gt;ev, fd, EV_WRITE, client_write, data);
    // Schedule client event
    event_add(&amp;amp;data-&amp;gt;ev, NULL);
}
//}}}

// Handle client responce {{{
void client_write(int fd, short event, void *arg)
{
    ConnectionData * data = reinterpret_cast&amp;lt;ConnectionData*&amp;gt;(arg);
    if (!data) {
        close(fd);
        return;
    }
    // Send data to client
    int len = write(fd, data-&amp;gt;buf + data-&amp;gt;offset, data-&amp;gt;size - data-&amp;gt;offset);
    if (len &amp;lt; data-&amp;gt;size - data-&amp;gt;offset) {
        // Failed to send rest data, need to reschedule
        data-&amp;gt;offset += len;
        event_set(&amp;amp;data-&amp;gt;ev, fd, EV_WRITE, client_write, data);
        // Schedule client event
        event_add(&amp;amp;data-&amp;gt;ev, NULL);
    }
    close(fd);
    delete data;
}
//}}}
&lt;/pre&gt;&lt;br /&gt;
В libevent есть простой асинхронный HTTP сервер, который можно встраивать в свое&lt;br /&gt;
приложение, а так же фреймворк для написания приложений, использующие RPC.&lt;div class="blogger-post-footer"&gt;&lt;a href="http://incpp.blogspot.com/"&gt;In C++. Программирование на C++ и не только...&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8518171411908930166-8016754255822023659?l=incpp.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/InCpp/~4/a2lkdPC1F_U" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/InCpp/~3/a2lkdPC1F_U/libevent.html</link><author>noreply@blogger.com (Андрей Булавинов)</author><thr:total>2</thr:total><feedburner:origLink>http://incpp.blogspot.com/2009/04/libevent.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8518171411908930166.post-1086149773456725630</guid><pubDate>Tue, 24 Mar 2009 16:24:00 +0000</pubDate><atom:updated>2009-03-24T18:25:17.450+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">баг</category><category domain="http://www.blogger.com/atom/ns#">libevent</category><category domain="http://www.blogger.com/atom/ns#">kqueue</category><category domain="http://www.blogger.com/atom/ns#">fifo</category><title>Асинхронный ввод/вывод с libevent</title><description>Один из проектов, которым я сейчас занимаюсь, для работы с сокетами использует механизм kqueue. Мне необходимо модифицировать бизнес-логику, часть которой захватывает отправку  отправку ответа, но поскольку некоторые данные приходится модифицировать непосредственно перед отправкой, код обработки события EVFILT_WRITE сильно размазался.&lt;br /&gt;  Я решил перенести сетевой асинхронный ввод/вывод на библиотеку libevent. На &lt;a href="http://monkey.org/%7Eprovos/libevent/"&gt;официальном сайте&lt;/a&gt;  есть неплохая документация в Doxygen и скудненький пример, который оказался не совсем рабочим: событие EV_READ срабатывает постоянно.&lt;br /&gt;Собрал на FreeBSD 6.2, 6.3, 7.0 – баг повторяется. Чтоб событие отрабатывалось корректно и вовремя, очередь надо открывать с правами O_RDWR, а не с O_RDONLY.&lt;div class="blogger-post-footer"&gt;&lt;a href="http://incpp.blogspot.com/"&gt;In C++. Программирование на C++ и не только...&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8518171411908930166-1086149773456725630?l=incpp.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/InCpp/~4/piNOV9gZUb8" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/InCpp/~3/piNOV9gZUb8/libevent.html</link><author>noreply@blogger.com (Андрей Булавинов)</author><thr:total>1</thr:total><feedburner:origLink>http://incpp.blogspot.com/2009/03/libevent.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8518171411908930166.post-788846128639545142</guid><pubDate>Tue, 10 Mar 2009 11:05:00 +0000</pubDate><atom:updated>2009-03-10T13:20:36.159+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">codecamp</category><category domain="http://www.blogger.com/atom/ns#">встречи</category><category domain="http://www.blogger.com/atom/ns#">конференция</category><title>CodeCamp 2009...</title><description>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://codecamp.org.ua"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 116px; height: 64px;" src="http://4.bp.blogspot.com/_ym1v0B1Pi48/SbZJ921owiI/AAAAAAAAB9M/NSYNPWUmkUY/s320/CodeCamp1.jpg" alt="" id="BLOGGER_PHOTO_ID_5311514137571410466" border="0" /&gt;&lt;/a&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:trebuchet ms;"&gt; ...или еще одна возможность встретиться и пообщаться вживую.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;28-29 марта 2009 года в городе Киев пройдет всеукраинская конференция, посвященная разработке программного обеспечения. Программа конференции многопоточна, так что заранее желательно определиться, куда идти.&lt;br /&gt;Помимо программирования, будут доклады по управлению и работе в команде.&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Зарегистрироваться можно &lt;/span&gt;&lt;/span&gt;&lt;a style="font-family: trebuchet ms;" href="http://codecamp.org.ua/register"&gt;здесь&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Думаю, будет интересно.&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;a href="http://incpp.blogspot.com/"&gt;In C++. Программирование на C++ и не только...&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8518171411908930166-788846128639545142?l=incpp.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/InCpp/~4/Nfn_q1gUKtw" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/InCpp/~3/Nfn_q1gUKtw/codecamp-2009.html</link><author>noreply@blogger.com (Андрей Булавинов)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_ym1v0B1Pi48/SbZJ921owiI/AAAAAAAAB9M/NSYNPWUmkUY/s72-c/CodeCamp1.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://incpp.blogspot.com/2009/03/codecamp-2009.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8518171411908930166.post-8986569862953704830</guid><pubDate>Sat, 07 Mar 2009 14:57:00 +0000</pubDate><atom:updated>2009-03-24T18:43:51.944+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">журналирование</category><category domain="http://www.blogger.com/atom/ns#">wxWidgets</category><category domain="http://www.blogger.com/atom/ns#">ведение логов</category><category domain="http://www.blogger.com/atom/ns#">wxLog</category><title>Прозрачное журналирование с wxLog</title><description>В wxWidgets есть отличный механизм журналирования wxLog.&lt;br /&gt;С его помощью можно решить проблему ведения лога одновременно в файл и, например, в текстовый контрол.&lt;br /&gt;&lt;br /&gt;Если необходимо выводить сообщения в файл не только в ANSI, а и в Unicode,&lt;br /&gt;то очень удобно использовать логгер wxLogStream.&lt;br /&gt;Для его использования, потребуется собрать (если еще не собрано) wxWidgets с выставленной поддержкой std потоков. Для этого необходимо выставить соответствующую&lt;br /&gt;директиву в файле setup.h:&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;#define wxUSE_STD_IOSTREAM 1&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;После этого, в приложении потребуется установить целевой логгер:&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;//wxTestApp.h&lt;br /&gt;// в классе приложения добавить мембер потока&lt;br /&gt;...&lt;br /&gt;#include&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;class wxTestApp: public wxApp&lt;br /&gt;{&lt;br /&gt;...&lt;br /&gt;private:&lt;br /&gt;   std::ofstream m_logStream;&lt;br /&gt;...&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;//wxTestApp.cpp&lt;br /&gt;// в OnInit() проинициализировать целевой логгер&lt;br /&gt;&lt;br /&gt;bool wxCDCreatorApp::OnInit() {&lt;br /&gt;   // задаем имя лога (в каталоге приложения, файл &lt;имя файла приложения&gt;.log&lt;br /&gt;   wxString logPath = wxPathOnly(wxGetApp().argv[0]) &lt;br /&gt;       + wxFileName::GetPathSeparator() &lt;br /&gt;       + GetAppName() &lt;br /&gt;       +  wxT(".log");&lt;br /&gt;   m_logStream.open(logPath.GetData());&lt;br /&gt;&lt;br /&gt;   // не забываем удалить предыдущий логгер&lt;br /&gt;   delete wxLog::SetActiveTarget(new wxLogStream(reinterpret_cast&amp;lt;std::ostream*&amp;gt;(&amp;amp;m_logStream)));&lt;br /&gt;&lt;br /&gt;   // можно работать&lt;br /&gt;   wxLogMessage(wxT("Запуск приложения..."));&lt;br /&gt;...&lt;br /&gt;// инициализация приложения&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// и в OnExit() закрываем поток&lt;br /&gt;int wxCDCreatorApp::OnExit()&lt;br /&gt;{   &lt;br /&gt;   wxLogMessage(wxT("Выход..."));&lt;br /&gt;   m_logStream.close();&lt;br /&gt;   return wxApp::OnExit();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;После этого, в любой части приложения возмножно с помощью функций wxLogMessage, wxLogDebug (только в отладочной версии),&lt;br /&gt;wxLogTrace вести журналирование. В результате работы, в лог пишутся сообщения в примерно таком формате:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;09:55:05: Запуск приложения...&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;a href="http://incpp.blogspot.com/"&gt;In C++. Программирование на C++ и не только...&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8518171411908930166-8986569862953704830?l=incpp.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/InCpp/~4/oeNGu8UqAoo" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/InCpp/~3/oeNGu8UqAoo/wxlog.html</link><author>noreply@blogger.com (Андрей Булавинов)</author><thr:total>0</thr:total><feedburner:origLink>http://incpp.blogspot.com/2009/03/wxlog.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8518171411908930166.post-6480416561670868656</guid><pubDate>Thu, 05 Mar 2009 00:08:00 +0000</pubDate><atom:updated>2009-06-12T10:30:07.777+03:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">avcap</category><category domain="http://www.blogger.com/atom/ns#">dv capture</category><category domain="http://www.blogger.com/atom/ns#">Windows SDK</category><category domain="http://www.blogger.com/atom/ns#">DirectX</category><category domain="http://www.blogger.com/atom/ns#">сборка</category><title>Сборка библиотеки avcap для Windows</title><description>Итак, поэкспериментировав с различными библиотеками захвата видео, я остановился&lt;br /&gt;на кроссплатформенной библиотеке avcap. Сайт проекта находится &lt;a href="http://sourceforge.net/projects/libavcap/"&gt;здесь&lt;/a&gt;.&lt;br /&gt;Отличная документация к библиотеке идет в пакете с проектом. Также, есть&lt;br /&gt;простенький, но понятный пример использования.&lt;br /&gt;&lt;br /&gt;Почему я выбрал именно avcap:&lt;br /&gt;1. Кроссплатформенность.&lt;br /&gt;  Реализация под Windows использует DirectShow, под Linux - V4L, под Mac OS X - QuickTime.&lt;br /&gt;2. Написана на C++.&lt;br /&gt;3. Работает достаточно стабильно.&lt;br /&gt;4. Легко интегрируется с С++ проектом.&lt;br /&gt;&lt;br /&gt;Из минусов стоит отметить проблемную сборку под Windows.&lt;br /&gt;Под Linux и Mac OS X сборка и установка не вызвала никаких проблем, стандартная процедура:&lt;br /&gt;&lt;pre&gt;./configure&lt;br /&gt;make&lt;br /&gt;sudo make install&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Для успешной сборки avcap под Windows (XP, Vista) необходимо подготовить следующее:&lt;br /&gt;1. Установить Microsoft Visual Studio (2008).&lt;br /&gt;2. Установить Microsoft DirectX SDK (2008 November).&lt;br /&gt;3. Установить Microsoft Windows SDK 7.&lt;br /&gt;4. Скопировать каталог&lt;br /&gt;  C:\Program Files\Microsoft SDKs\Windows\v7.0\Samples\Multimedia\DirectShow\BaseClasses\&lt;br /&gt;&lt;br /&gt;  например в C:\Temp.&lt;br /&gt;5. Снять атрибут "Только чтение с BaseClasses".&lt;br /&gt;6. Открыть baseclasses.sln, согласиться на конвертацию в новый формат.&lt;br /&gt;7. Выбрать цель Debug.&lt;br /&gt;8. В зависимости от проекта, возможно прийдется изменить &lt;b&gt;Runtime Library&lt;/b&gt; на Multi-threaded Debug.&lt;br /&gt;9. Собрать.&lt;br /&gt;10. В настройках путей Visual Studio убедиться, что пути к DirectX SDK находяться ниже,&lt;br /&gt;   чем пути Windows SDK.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;a href="http://1.bp.blogspot.com/_ym1v0B1Pi48/Sa8SGj3FbHI/AAAAAAAAB8I/j46hxI5867Q/s1600-h/VS_Include_Path.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img src="http://1.bp.blogspot.com/_ym1v0B1Pi48/Sa8SGj3FbHI/AAAAAAAAB8I/j46hxI5867Q/s320/VS_Include_Path.png" style="cursor: move;" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;11. С предыдущего Platform SDK взять qedit.h и закоментировать в нем упоминания&lt;br /&gt;   dxtrans.h и  IDXEffect. Этот файл можно положить в каталог baseclasses.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Настройка проекта avcap.&lt;br /&gt;1. Открыть avcap.sln, согласиться сконвертировать.&lt;br /&gt;2. В свойствах проекта указать:&lt;br /&gt;&lt;b&gt;Character Set&lt;/b&gt;: Use Unicode Character Set&lt;br /&gt;&lt;b&gt;Additional Include Directories&lt;/b&gt;: C:\Temp\BaseClasses;C:\Program Files\Microsoft SDKs\Windows\v7.0\Include";..\include\avcap\windows;..\include\avcap;&lt;br /&gt;&lt;b&gt;Runtime Library&lt;/b&gt;: Multi-threaded Debug (/MTd)&lt;br /&gt;4. Открываем файл avcap\avcap\windows\&lt;b&gt;ds_devicedescriptor.cpp&lt;/b&gt;&lt;br /&gt;находим строчку (477) и правим ее:&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;wsprintf((LPWSTR)ws, L"FilterGraph %08x pid %08x\0", (DWORD_PTR)pUnkGraph, GetCurrentProcessId());&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;5.Собираем библиотеку.&lt;br /&gt;&lt;br /&gt;В настройки приложения, которое будет использовать avcap, нужно добавить следующее:&lt;br /&gt;в C/C++:&lt;br /&gt;&lt;b&gt;Preprocessor Definitions&lt;/b&gt;: AVCAP_WINDOWS&lt;br /&gt;и в Linker:&lt;br /&gt;&lt;b&gt;Additional Dependencies&lt;/b&gt;: avcapd.lib strmbasd.lib uuid.lib ole32.lib winmm.lib strmiids.lib oleaut32.lib&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Сборка была протестирована на Windows XP SP2 и на Windows Vista SP1.&lt;br /&gt;Основной источник проблем заключался в порядке путей к заголовочным файлам,&lt;br /&gt;так что будьте внимательнее.&lt;div class="blogger-post-footer"&gt;&lt;a href="http://incpp.blogspot.com/"&gt;In C++. Программирование на C++ и не только...&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8518171411908930166-6480416561670868656?l=incpp.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/InCpp/~4/-CdLgqxO9K0" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/InCpp/~3/-CdLgqxO9K0/avcap-windows.html</link><author>noreply@blogger.com (Андрей Булавинов)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_ym1v0B1Pi48/Sa8SGj3FbHI/AAAAAAAAB8I/j46hxI5867Q/s72-c/VS_Include_Path.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://incpp.blogspot.com/2009/03/avcap-windows.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8518171411908930166.post-3120942264111758751</guid><pubDate>Tue, 03 Mar 2009 20:33:00 +0000</pubDate><atom:updated>2009-03-05T01:44:59.182+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Platform SDK</category><category domain="http://www.blogger.com/atom/ns#">avcap</category><category domain="http://www.blogger.com/atom/ns#">Windows SDK</category><category domain="http://www.blogger.com/atom/ns#">wdh</category><category domain="http://www.blogger.com/atom/ns#">DirectX</category><title>Сборка Windows SDK 7</title><description>После установки, первое, что удивило - это замена makefile в Samples на sln+vcproj.&lt;br /&gt;Хоть что-то изменилось.&lt;br /&gt;&lt;br /&gt;Скопировал весь каталог BaseClasses в рабочий каталог и открыл в студии проект.&lt;br /&gt;Студия предложила сконвертировать в новый формат. Сконвертировал, собираю...&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;gt;amfilter.cpp&lt;br /&gt;1&amp;gt;c:\program files\microsoft sdks\windows\v7.0\include\objidl.h(11265) :&lt;br /&gt;error C2061: syntax error : identifier '__RPC__out_xcount_part'&lt;br /&gt;1&amp;gt;c:\program files\microsoft sdks\windows\v7.0\include\objidl.h(11266) :&lt;br /&gt;error C2059: syntax error : ')'&lt;br /&gt;1&amp;gt;c:\program files\microsoft sdks\windows\v7.0\include\objidl.h(11266) :&lt;br /&gt;fatal error C1903: unable to recover from previous error(s); stopping compilation&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Проблема оказалась в путях к заголовочным файлам, вернее в их порядке.&lt;br /&gt;Переместив C:\Program Files (x86)\Microsoft DirectX SDK\Include в самый конец все&lt;br /&gt;собралось на отлично.&lt;br /&gt;&lt;br /&gt;Сборка avcap.&lt;br /&gt;&lt;br /&gt;В 7 SDK удалили файл qedit.h!&lt;br /&gt;Взял этот файл из SDK 6.0A.&lt;br /&gt;Вернулась проблема dxtrans.h, которого все-таки больше не существует.&lt;br /&gt;&lt;br /&gt;Отредактировал qedit.h&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;&lt;br /&gt;//#include "dxtrans.h" -- Line 498&lt;br /&gt;IDxtCompositor //: public IDXEffect -- Line 837&lt;br /&gt;IDxtAlphaSetter //: public IDXEffect -- Line 1151&lt;br /&gt;IDxtJpeg //: public IDXEffect -- Line 1345&lt;br /&gt;IDxtKey //: public IDXEffect -- Line 1735&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Пересобираю... опять гора ошибок.&lt;br /&gt;Оказывается, в SDK есть такие же заголовочные файлы, как и в&lt;br /&gt;Samples\Multimedia\DirectShow\BaseClasses. Ладно, переставил порядок,&lt;br /&gt;поставил Samples перед SDK.&lt;br /&gt;Пересобираю...&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;1&amp;gt;c:\temp\avcap\avcap\windows\ds_devicedescriptor.cpp(477) :&lt;br /&gt;error C2664: 'wsprintfW' : cannot convert parameter 1 from 'char [128]' to 'LPWSTR'&lt;br /&gt;1&amp;gt;        Types pointed to are unrelated; conversion requires reinterpret_cast,&lt;br /&gt;C-style cast or function-style cast&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;"Жопой чую, конец близко" (с) Макс&lt;br /&gt;&lt;br /&gt;Быстро поправляю типы данных и преобразования, пересобираю и вуаля!&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;1&amp;gt;avcap - 0 error(s), 0 warning(s)&lt;br /&gt;2&amp;gt;captest - 0 error(s), 0 warning(s)&lt;br /&gt;========== Build: 2 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Протестировал, все работает на отлично.&lt;br /&gt;&lt;br /&gt;Все просто!&lt;div class="blogger-post-footer"&gt;&lt;a href="http://incpp.blogspot.com/"&gt;In C++. Программирование на C++ и не только...&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8518171411908930166-3120942264111758751?l=incpp.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/InCpp/~4/LfkjtcW4HZU" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/InCpp/~3/LfkjtcW4HZU/windows-sdk-7.html</link><author>noreply@blogger.com (Андрей Булавинов)</author><thr:total>4</thr:total><feedburner:origLink>http://incpp.blogspot.com/2009/03/windows-sdk-7.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8518171411908930166.post-5265954210732537132</guid><pubDate>Sun, 01 Mar 2009 20:17:00 +0000</pubDate><atom:updated>2009-03-12T12:50:07.538+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Platform SDK</category><category domain="http://www.blogger.com/atom/ns#">avcap</category><category domain="http://www.blogger.com/atom/ns#">BaseClasses</category><title>Windows Development Hell</title><description>Текущий проект заставил меня вернуться к программированию под Windows.&lt;br /&gt;
Прошло два дня активной работы и у меня уже сдают нервы.&lt;br /&gt;
Я конечно все понимаю, но не так же все плохо?&lt;br /&gt;
&lt;br /&gt;
Собираю библиотеку libavcap. Она требует Platform SDK, ок, ставлю.&lt;br /&gt;
Дальше, BaseClasses захотели DirectX SDK. Ну, скачал поставил.&lt;br /&gt;
А оно не работает! Оказывается разработчики или ответственные за&lt;br /&gt;
сборку пакета "забыли" добавить файлик &lt;a href="http://social.msdn.microsoft.com/Forums/en-US/windowssdk/thread/ed097d2c-3d68-4f48-8448-277eaaf68252/"&gt;dxtrans.h&lt;/a&gt;, начал гуглить, действительно.&lt;br /&gt;
Причем, эта проблема, как я понял, уже с давних пор. Ждут исправления в Windows 7. Шок.&lt;br /&gt;
&lt;br /&gt;
Порадовал дизайн инсталлятора DirectX.&lt;br /&gt;
Почему именно Check Box там, где должен быть Radio Button? Умом их не понять...&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;a href="http://1.bp.blogspot.com/_ym1v0B1Pi48/Sarq3eLftPI/AAAAAAAAB7g/XRIa2dgCjZI/s1600-h/dx_install.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img src="http://1.bp.blogspot.com/_ym1v0B1Pi48/Sarq3eLftPI/AAAAAAAAB7g/XRIa2dgCjZI/s320/dx_install.jpg" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Собирая strmbasd.lib, намучался с путями Development Environment Command Prompts.&lt;br /&gt;
То они видят cl и не видят link, то не видят вообще ничего...&lt;br /&gt;
&lt;br /&gt;
Во время сборки nmake останавливался раза четыре. Из-за ошибок в коде.&lt;br /&gt;
&lt;br /&gt;
Например, в файле outputq.cpp:635 был код, примерно следующего вида:&lt;br /&gt;
&lt;pre class="cpp" name="code"&gt;for (long iDone = 0;....;) {
}
*nSamplesProcessed = iDone - iLost;
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
Старый стандарт, это понятно. Но SDK-то не старый!!!&lt;br /&gt;
И так еще в 3 файлах и более чем в 10 местах. Поправив все вручную, вроде собралось.&lt;br /&gt;
&lt;br /&gt;
Кстати, при сборке и запуске Register Development Environment Variables у меня пропал файл,&lt;br /&gt;
или студия начала ссылаться на несуществующий... mspdb80.dll&lt;br /&gt;
&lt;br /&gt;
Нашел, скопировал, студия перестала вообще что-либо собирать.&lt;br /&gt;
Вручную отредактировал пути поиска програм и библиотек,&lt;br /&gt;
удалил библиотеку - вроде заработало.&lt;br /&gt;
&lt;br /&gt;
Итого, двое суток мозгосношений и ни строчки собственного кода в попытке сборки чужого.&lt;br /&gt;
&lt;br /&gt;
Становится все интереснее...&lt;div class="blogger-post-footer"&gt;&lt;a href="http://incpp.blogspot.com/"&gt;In C++. Программирование на C++ и не только...&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8518171411908930166-5265954210732537132?l=incpp.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/InCpp/~4/Pl3u1mITjIU" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/InCpp/~3/Pl3u1mITjIU/windows-development-hell.html</link><author>noreply@blogger.com (Андрей Булавинов)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_ym1v0B1Pi48/Sarq3eLftPI/AAAAAAAAB7g/XRIa2dgCjZI/s72-c/dx_install.jpg" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://incpp.blogspot.com/2009/03/windows-development-hell.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8518171411908930166.post-7879182079769815266</guid><pubDate>Fri, 06 Feb 2009 13:49:00 +0000</pubDate><atom:updated>2009-04-23T18:09:13.641+03:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">качество кода</category><category domain="http://www.blogger.com/atom/ns#">warnings</category><title>Сборка без warnings</title><description>Довелось работать с модулями системы, которые девелопил не я. Первым делом попробовал собрать. &lt;br /&gt;
Не знаю, как кого, но сборка с warnings лично меня сильно напрягает. &lt;br /&gt;
Поэтому, я решил причесать их немного.&lt;br /&gt;
&lt;br /&gt;
Одно из проблемыных мест было множественно сообщение компилятора &lt;br /&gt;
"deprecated conversion from string constant to 'char *'". &lt;br /&gt;
Раньше модули собирались gcc версии 3.4, а сейчас 4.2, поэтому сборка была более тихая.&lt;br /&gt;
&lt;br /&gt;
Код оказался винегредом из С и С++, причем для строк использовался именно char *, &lt;br /&gt;
менять на std::string было бы долго и неоправданно. Как оказалось, проблема была в следующем:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="cpp" name="code"&gt;void addpack(std::vector&amp;lt;uint8_t&amp;gt;&amp;amp; c, char * formatt,...) {
    // большой switch, проверяющий посимвольно значение ключей
}

void addPack64(std::vector&amp;lt;uint8_t&amp;gt; &amp;amp;c, uint64_t iValue) {                                                            
    addpack(c, "N", (uint32_t)(iValue &amp;gt;&amp;gt; 32) );              
    addpack(c, "N", (uint32_t)(iValue &amp;amp; 0xffffffffUL));
}

&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
Как видно из кода, функции addpack передавался указатель на локальную константную строку с возможностью изменения ее содержимого.&lt;br /&gt;
&lt;br /&gt;
В качестве решения, параметр &lt;span style="font-weight: bold;"&gt;char * formatt&lt;/span&gt; был заменен на &lt;span style="font-weight: bold;"&gt;const char * formatt&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;a href="http://incpp.blogspot.com/"&gt;In C++. Программирование на C++ и не только...&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8518171411908930166-7879182079769815266?l=incpp.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/InCpp/~4/d63_ShEV7yQ" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/InCpp/~3/d63_ShEV7yQ/warnings.html</link><author>noreply@blogger.com (Андрей Булавинов)</author><thr:total>0</thr:total><feedburner:origLink>http://incpp.blogspot.com/2009/02/warnings.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8518171411908930166.post-4702517859350194452</guid><pubDate>Mon, 20 Oct 2008 16:26:00 +0000</pubDate><atom:updated>2008-10-21T15:22:38.949+03:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ошибки</category><category domain="http://www.blogger.com/atom/ns#">pure virtual call</category><title>Вызов pure virtual метода</title><description>Обсуждали различные ситуации, связанные с inline функциями, и вспомнился прикол исключения: Pure virual function call. Действительно, имеет место такое.&lt;br /&gt;Подробно расписано тут &lt;a href="http://www.artima.com/cppsource/pure_virtual.html"&gt;http://www.artima.com/cppsource/pure_virtual.html&lt;/a&gt;&lt;br /&gt;Бывают в жизни проблемы...&lt;div class="blogger-post-footer"&gt;&lt;a href="http://incpp.blogspot.com/"&gt;In C++. Программирование на C++ и не только...&lt;/a&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8518171411908930166-4702517859350194452?l=incpp.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/InCpp/~4/-MbeJjD1iCw" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/InCpp/~3/-MbeJjD1iCw/pure-virtual.html</link><author>noreply@blogger.com (Андрей Булавинов)</author><thr:total>0</thr:total><feedburner:origLink>http://incpp.blogspot.com/2008/10/pure-virtual.html</feedburner:origLink></item></channel></rss>

