<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Yoichi Kawasaki&#039;s Web &#187; http</title>
	<atom:link href="http://yk55.com/blog/tags/http/feed/" rel="self" type="application/rss+xml" />
	<link>http://yk55.com/blog</link>
	<description>my publicly accessible private memorandums</description>
	<lastBuildDate>Mon, 14 May 2012 01:31:02 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
	<!-- google_ad_section_end --><!-- google_ad_section_start(weight=ignore) -->	<item>
		<title>AWK HTTPサーバ</title>
		<link>http://yk55.com/blog/2010/06/29/awk_http/</link>
		<comments>http://yk55.com/blog/2010/06/29/awk_http/#comments</comments>
		<pubDate>Mon, 28 Jun 2010 23:04:02 +0000</pubDate>
		<dc:creator>yoichi</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[awk]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[igawk]]></category>
		<category><![CDATA[net]]></category>
		<category><![CDATA[network]]></category>

		<guid isPermaLink="false">http://yk55.com/blog/?p=383</guid>
		<description><![CDATA[AWK Users JPの中で紹介されている簡易HTTPサーバをベースに少しだけ機能追加してみた。例では固定の文字列しか扱っていなかったので最低限リクエストしたパスに従いそのファイルを表示できるようにした。 ソースコード – httpd.awk http://github.com/yokawasa/any/tree/master/awk_httpd/ http://github.com/yokawasa/any/blob/master/awk_httpd/httpd.awk #! /usr/bin/gawk -f BEGIN { &#160; &#160; port = &#34;8080&#34;; &#160; &#160; docroot = &#34;./&#34;; &#160; &#160; http_service = &#34;/inet/tcp/&#34; port &#34;/0/0&#34;; &#160; &#160; RS = ORS = &#34;\r\n&#34;; &#160; &#160; for (;;) { &#160; &#160; &#160; &#160;if ((http_service &#124;&#38; getline reqline) &#62; 0) { &#160; &#160; [...]]]></description>
			<content:encoded><![CDATA[<p>AWK Users JPの中で紹介されている<a href="http://gauc.no-ip.org/awk-users-jp/blis.cgi/DoukakuAWK_065">簡易HTTPサーバ</a>をベースに少しだけ機能追加してみた。例では固定の文字列しか扱っていなかったので最低限リクエストしたパスに従いそのファイルを表示できるようにした。</p>
<p><h2><strong>ソースコード – httpd.awk</strong></h2>
<p><a href="http://github.com/yokawasa/any/tree/master/awk_httpd/">http://github.com/yokawasa/any/tree/master/awk_httpd/</a><br />
<a href="http://github.com/yokawasa/any/blob/master/awk_httpd/httpd.awk">http://github.com/yokawasa/any/blob/master/awk_httpd/httpd.awk</a></p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#! /usr/bin/gawk -f<br />
<br />
BEGIN {<br />
&nbsp; &nbsp; port = &quot;8080&quot;;<br />
&nbsp; &nbsp; docroot = &quot;./&quot;;<br />
&nbsp; &nbsp; http_service = &quot;/inet/tcp/&quot; port &quot;/0/0&quot;;<br />
&nbsp; &nbsp; RS = ORS = &quot;\r\n&quot;;<br />
&nbsp; &nbsp; for (;;) {<br />
&nbsp; &nbsp; &nbsp; &nbsp;if ((http_service |&amp; getline reqline) &gt; 0) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; request_handler(http_service, reqline, docroot);<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp;close(http_service);<br />
&nbsp; &nbsp; }<br />
}<br />
<br />
function request_handler(http_service,reqline, docroot) {<br />
&nbsp; &nbsp; # parse request line<br />
&nbsp; &nbsp; if ( split(reqline, t, &quot; &quot;) !=3 ) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; show_error(http_service, 400, &quot;Bad Request&quot;);<br />
&nbsp; &nbsp; &nbsp; &nbsp; return 1;<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; req_method = t[1];<br />
&nbsp; &nbsp; req_uri = (index(t[2], &quot;/&quot;)==1) ? substr(t[2],2) : t[2];<br />
&nbsp; &nbsp; if (req_method != &quot;GET&quot; ) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; show_error(http_service, 405, &quot;Method Not Allowed&quot;);<br />
&nbsp; &nbsp; &nbsp; &nbsp;return 1;<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; # set path and query string<br />
&nbsp; &nbsp; path = docroot req_uri;<br />
&nbsp; &nbsp; n = split(path,tt,&quot;?&quot;);<br />
&nbsp; &nbsp; if (n &gt;=2 ) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; path = tt[1];<br />
&nbsp; &nbsp; &nbsp; &nbsp; ENVIRON[&quot;QUERY_STRING&quot;] = tt[2];<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; # path should end with &quot;/&quot; if it's directory.<br />
&nbsp; &nbsp; if(dir_exists(path)) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; if (substr(path,length(path)) != &quot;/&quot;) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; path = path &quot;/&quot;;<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp; # set default file<br />
&nbsp; &nbsp; &nbsp; &nbsp; path = path &quot;index.html&quot;;<br />
&nbsp; &nbsp; }<br />
<br />
&nbsp; &nbsp; # check if file exists<br />
&nbsp; &nbsp; if (!file_exists(path)) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; show_error(http_service, 404, &quot;Not Found&quot;);<br />
&nbsp; &nbsp; &nbsp; &nbsp;return 1;<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; show_page(http_service, path);<br />
&nbsp; &nbsp; return 0;<br />
}<br />
<br />
function file_exists(path) {<br />
&nbsp; &nbsp; cmd =&quot;if [ -f &quot; path &quot; ]; then echo OK; fi&quot;;<br />
&nbsp; &nbsp; exist = 0;<br />
&nbsp; &nbsp; if ( (cmd |getline res) &gt; 0) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; gsub(&quot;\n&quot;,&quot;&quot;, res);<br />
&nbsp; &nbsp; &nbsp; &nbsp; if (res == &quot;OK&quot;) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; exist = 1;<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; close(cmd);<br />
&nbsp; &nbsp; return exist;<br />
}<br />
<br />
function dir_exists(path) {<br />
&nbsp; &nbsp; cmd =&quot;if [ -d &quot; path &quot; ]; then echo OK; fi&quot;;<br />
&nbsp; &nbsp; exist = 0;<br />
&nbsp; &nbsp; if ( (cmd |getline res) &gt; 0) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; gsub(&quot;\n&quot;,&quot;&quot;, res);<br />
&nbsp; &nbsp; &nbsp; &nbsp; if (res == &quot;OK&quot;) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; exist = 1;<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; close(cmd);<br />
&nbsp; &nbsp; return exist;<br />
}<br />
<br />
function file_read(file) {<br />
&nbsp; &nbsp; buf = &quot;&quot;;<br />
&nbsp; &nbsp; while (getline &lt; file &gt; 0) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;buf = buf $0;<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; close(file);<br />
&nbsp; &nbsp; return buf;<br />
}<br />
<br />
function find_mime_type(path) {<br />
&nbsp; &nbsp; mime_type = &quot;application/ocet-stream&quot;; # default mime type<br />
&nbsp; &nbsp; n = split(path, t, &quot;/&quot;);<br />
&nbsp; &nbsp; if (n &gt;=2 ) { &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; filename = t[n];<br />
&nbsp; &nbsp; &nbsp; &nbsp; m = split(filename, tt, &quot;.&quot;);<br />
&nbsp; &nbsp; &nbsp; &nbsp; if (m &gt;=2 ) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ext = tolower(tt[m]);<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (ext == &quot;html&quot; || ext == &quot;htm&quot;) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mime_type = &quot;text/html&quot;;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }else if (ext == &quot;css&quot; ) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mime_type = &quot;text/css&quot;;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }else if (ext == &quot;txt&quot; || ext == &quot;text&quot; ) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mime_type = &quot;text/plain&quot;;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; return mime_type;<br />
}<br />
<br />
function show_page( http_service,path) {<br />
&nbsp; &nbsp; outbuf = file_read(path);<br />
&nbsp; &nbsp; mime_type = find_mime_type(path);<br />
&nbsp; &nbsp; content_len = length(buf);<br />
&nbsp; &nbsp; print_output(http_service,200,&quot;OK&quot;,outbuf,mime_type,content_len);<br />
}<br />
<br />
function show_error( http_service, errcode, reason) {<br />
&nbsp; &nbsp; outbuf = &quot;&lt;h1&gt;&quot; reason &quot;&lt;/h1&gt;&quot;;<br />
&nbsp; &nbsp; mime_type = &quot;text/html&quot;;<br />
&nbsp; &nbsp; content_len = length(buf);<br />
&nbsp; &nbsp; print_output(http_service,errcode,reason,outbuf,mime_type,content_len);<br />
}<br />
<br />
function print_output( http_service,code,reason,outbuf,mime_type,content_len) {<br />
&nbsp; &nbsp; print &quot;HTTP/1.x &quot; code &quot; &quot; reason |&amp; http_service;<br />
&nbsp; &nbsp; print &quot;Content-type: &quot; mime_type |&amp; http_service;<br />
&nbsp; &nbsp; print &quot;Content-Length: &quot; content_len |&amp; http_service;<br />
&nbsp; &nbsp; print &quot;&quot; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&amp; http_service;<br />
&nbsp; &nbsp; print outbuf |&amp; http_service;<br />
}</div></div>
<p>このプログラムの肝はgawkネットワーク接続用ファイル表記/inet/～でTCP/IPネットワーク接続の利用を宣言しhttp_service変数に格納、 &#8216;|&#038;&#8217; オペレータでINPUTとOUTPUTの2方向のネットワーク接続パイプを作成し、 ネットワーク接続パイプラインからのINPUT内容は&#8221; http_service |&#038; getline&#8217; で受けとり、 OUTPUT内容は &#8216; print &#8220;書き込む内容&#8221; |&#038; http_service&#8217;  で書き込む。 これに尽きる。</p>
<ul>
<li><a href="http://www.gnu.org/manual/gawk/html_node/TCP_002fIP-Networking.html#TCP_002fIP-Networking">ネットワーク通信用ファイル表記について &#8211; Using gawk  for Network Programming</a></li>
<li><a href="http://www.gnu.org/manual/gawk/html_node/Two_002dway-I_002fO.html#Two_002dway-I_002fO">他プロセスとの2方向(IN、OUT)通信について &#8211; Two-Way Communications with Another Process</a></li>
</ul>
<p><p>
あと、残念なことにAWKはバイナリーデータが扱えない。よってHTTPサーバとしては致命的ではあるが画像やその他メディアファイルの表示をすることができない。 このHTTPサーバでは .htm、.html、.css、.txtファイルに対してはそれぞれMIMEタイプを&#8217;text/html&#8217;、&#8217;text/css&#8217;、&#8217;text/plain&#8217;としているがそれ以外のファイルタイプに対しては一律&#8217;application/ocet-stream&#8217;としている。</p>
<p><h2><strong>サーバ起動、サンプルページの表示</strong></h2>
<p>git clone でソースコードを取得する。リポジトリanyのサブディレクトリ any/awk_httpdが今回のサンプルにあたる。そして取得したhttpd.awkをgawkのファイル指定で実行する。gawkのパスが/usr/bin/gawkな場合は直接 ./httpd.awkで実行すればよい。 httpd.awkはデフォルトでポートが8080、ドキュメントルートが&#8221;./&#8221;となっている。ちなみに同一ディレクトリにポートとドキュメントルートのオプション指定ができる<a href="http://github.com/yokawasa/any/blob/master/awk_httpd/httpd.igawk">httpd.igawk</a>を用意している。 これを使用するには実行環境にigawkシェルスクリプトがインストールされている必要がある。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ git clone git@github.com:yokawasa/any.git &nbsp;<br />
Initialized empty Git repository in /home/m/dev/github/t/any/.git/<br />
remote: Counting objects: 45, done.<br />
remote: Compressing objects: 100% (44/44), done.<br />
remote: Total 45 (delta 11), reused 0 (delta 0)<br />
Receiving objects: 100% (45/45), 13.99 KiB, done.<br />
Resolving deltas: 100% (11/11), done<br />
<br />
$ cd any/awk_httpd<br />
<br />
$ ls -1 <br />
httpd.awk<br />
httpd.igawk<br />
pages<br />
<br />
$ gawk -f ./httpd.awk</div></div>
<p>ページ表示テスト用にany/awk_httpd/pages下にhtml、cssファイルを用意してあるのでこれらを/home/awk_httpd/pages配下に配置して実際にブラウザでindex.htmlを表示させてみる。成功すると以下のようなページが表示される。</p>
<p><a href="http://www.flickr.com/photos/yk55/4743945384/" title="AWK HTTP Server Page by yoichi*, on Flickr"><img src="http://farm5.static.flickr.com/4115/4743945384_2fa7426d09_z.jpg" width="640" height="315" alt="AWK HTTP Server Page"></a></p>
<p>おわり。</p>
<iframe src="http://www.facebook.com/plugins/like.php?href=http://yk55.com/blog/2010/06/29/awk_http/&amp;layout=button_count&amp;show_faces=1&amp;width=450&amp;action=like&amp;colorscheme=light&amp;font=arial" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:25px"></iframe>]]></content:encoded>
			<wfw:commentRss>http://yk55.com/blog/2010/06/29/awk_http/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>LibeventのRPCフレームワークによるC/Sプログラミング</title>
		<link>http://yk55.com/blog/2010/06/05/libevent_rpc_cs_programmin/</link>
		<comments>http://yk55.com/blog/2010/06/05/libevent_rpc_cs_programmin/#comments</comments>
		<pubDate>Sat, 05 Jun 2010 14:49:21 +0000</pubDate>
		<dc:creator>yoichi</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[c]]></category>
		<category><![CDATA[cplusplus]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[libevent]]></category>
		<category><![CDATA[network]]></category>
		<category><![CDATA[rpc]]></category>

		<guid isPermaLink="false">http://yk55.com/blog/?p=361</guid>
		<description><![CDATA[前回の投稿ではlibeventのHTTP処理機能evhttpを使ったHTTPサーバを紹介したが今回はlibeventのRPCフレームワーク evrpcを使ったC/Sプログラミング方法を紹介してみる。このevrpcはかなりマイナーな部類のフレームワークといえる。これに関するドキュメントは少なく、検索してみるとまともなページがヒットしない。ヘッダやテストコードを読まない人にとってはちょっと厳しいかもしれない。 巷にはハイパフォーマンスで使いやすく少し検索すれば豊富なドキュメントやブログ記事がわさわさと出てくるようなフレームワークがごろごろしているのでこんなに地味で愛想ないフレームワークをふつーは選ばない。 そんな人気のないevrpcだけど実際に使ってみると思ったより悪くない。 動作は安定しているしAPIはシンプルで使いやすく拡張性も考慮されていてHook関数、Callback関数を駆使すれば好きに振る舞いを制御することができる。 少々粗挽きなところは全く気にしないでこれをベースに自分なりに使いやすいフレームワークを作ってやろうくらいに思ってる人には向いているかもしれない。 RPC marshalling用コードのジェネレート &#8211; event_rpcgen.py marshallingとはRPC C/S処理で内部的に使用するデータ構造をネットワーク転送用のフォーマットに変換することで、その逆をdemarshallingと呼ぶ。厳密には意味が違うらしいがserializationとdeserializationみたいなもの。 libeventにはデータ構造をmarshalling、demarshallingするコードをジェネレートするためのスクリプトが用意されている。それがevent_rpcgen.py。RPC C/S処理で使用するデータ構造を定められたフォーマットで定義してやりそれをevent_rpcgen.pyに食わせてやることでコードが生成される。 データ構造の定義フォーマットは次のとおり。 [データ構造の定義フォーマット] struct &#60;data struct name&#62; { &#160; &#160; [optional] &#60;type&#62; &#60;varname&#62; = &#60;index&#62;; &#160; &#160; &#160;... } &#60;type&#62; データ型 &#160; - string &#160;文字列 &#160; - bytes &#160;uint_tベクター。 [lenght]で長さを指定。　例、bytes hoge[10] &#160; - int &#160;uint32_t &#160; - struct[structname] &#160;構造体 &#160; - array [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://yk55.com/blog/2010/04/30/eventdriven_http_server_vs_httpd/">前回の投稿</a>では<a href="http://www.monkey.org/~provos/libevent/">libevent</a>のHTTP処理機能<a href="http://www.monkey.org/~provos/libevent/doxygen-1.4.10/evhttp_8h.html">evhttp</a>を使ったHTTPサーバを紹介したが今回はlibeventのRPCフレームワーク <a href="http://www.monkey.org/~provos/libevent/doxygen-1.4.10/evrpc_8h.html">evrpc</a>を使ったC/Sプログラミング方法を紹介してみる。このevrpcはかなりマイナーな部類のフレームワークといえる。これに関するドキュメントは少なく、検索してみるとまともなページがヒットしない。ヘッダやテストコードを読まない人にとってはちょっと厳しいかもしれない。 巷にはハイパフォーマンスで使いやすく少し検索すれば豊富なドキュメントやブログ記事がわさわさと出てくるようなフレームワークがごろごろしているのでこんなに地味で愛想ないフレームワークをふつーは選ばない。 そんな人気のないevrpcだけど実際に使ってみると思ったより悪くない。 動作は安定しているしAPIはシンプルで使いやすく拡張性も考慮されていてHook関数、Callback関数を駆使すれば好きに振る舞いを制御することができる。 少々粗挽きなところは全く気にしないでこれをベースに自分なりに使いやすいフレームワークを作ってやろうくらいに思ってる人には向いているかもしれない。</p>
<p><h2><strong>RPC marshalling用コードのジェネレート &#8211; event_rpcgen.py</strong></h2>
<p><a href="http://en.wikipedia.org/wiki/Marshalling_%28computer_science%29">marshalling</a>とはRPC C/S処理で内部的に使用するデータ構造をネットワーク転送用のフォーマットに変換することで、その逆をdemarshallingと呼ぶ。厳密には意味が違うらしいがserializationとdeserializationみたいなもの。 libeventにはデータ構造をmarshalling、demarshallingするコードをジェネレートするためのスクリプトが用意されている。それが<a href="http://levent.git.sourceforge.net/git/gitweb.cgi?p=levent/levent;a=blob;f=event_rpcgen.py;h=05f0a3622aa7d9343d8f3e86f6c42fc0465e46ae;hb=HEAD">event_rpcgen.py</a>。RPC C/S処理で使用するデータ構造を定められたフォーマットで定義してやりそれをevent_rpcgen.pyに食わせてやることでコードが生成される。 データ構造の定義フォーマットは次のとおり。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[データ構造の定義フォーマット]<br />
<br />
struct &lt;data struct name&gt; {<br />
&nbsp; &nbsp; [optional] &lt;type&gt; &lt;varname&gt; = &lt;index&gt;;<br />
&nbsp; &nbsp; &nbsp;...<br />
}<br />
<br />
&lt;type&gt; データ型<br />
&nbsp; - string &nbsp;文字列<br />
&nbsp; - bytes &nbsp;uint_tベクター。 [lenght]で長さを指定。　例、bytes hoge[10]<br />
&nbsp; - int &nbsp;uint32_t<br />
&nbsp; - struct[structname] &nbsp;構造体<br />
&nbsp; - array &lt;type&gt; &nbsp;typeで指定されたデータ型のベクター。 typeはstring, bytes, int, または struct[structname]<br />
<br />
&lt;varname&gt; 変数名<br />
&lt;index&gt; インデックス番号。フィールド番号。<br />
<br />
[optional] &nbsp;typeの前にoptionalを指定するとリクエスト、レスポンス処理時にそのフィールドへのデータセットを省略することができる。<br />
<br />
※ &nbsp;定義ファイルの拡張子は.rpcである必要がある<br />
※ &nbsp;&lt;varname&gt; と&lt;index&gt;の間は１半角スペースずつを開ける。 そうでない場合はevent_rpcgen.pyによるジェネレートが失敗するので要注意！<br />
&nbsp; &nbsp;× &nbsp; &nbsp;int errcode =1;<br />
&nbsp; &nbsp;× &nbsp; &nbsp;int errcode &nbsp; = 1;<br />
&nbsp; &nbsp;× &nbsp; &nbsp;int errcode=1;<br />
&nbsp; &nbsp;○ &nbsp; &nbsp;int errcode = 1</div></div>
<p>今回のサンプルで使用するデータ構造を定義する。 サンプルはユーザ情報を取得するRPCでありユーザ情報取得のためのリクエスト、レスポンス用データ構造が以下のGetUserRequest、GetUserResponse。</p>
<p><u>サンプルデータ構造の定義フォーマットファイル &#8211; <A href="http://github.com/yokawasa/any/blob/master/libevent_rpc/simple.rpc">simple.rpc</A></u></p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">struct</span> GetUserRequest <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; string id <span style="color: #339933;">=</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #993333;">struct</span> GetUserResponse <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">int</span> errcode <span style="color: #339933;">=</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; optional string name <span style="color: #339933;">=</span> <span style="color: #0000dd;">2</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; optional string email <span style="color: #339933;">=</span> <span style="color: #0000dd;">3</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>これを次のようにevent_rpcgen.pyを使ってデータ構造定義からコードをジェネレートする。 event_rpcgen.pyはlibeventをインストールするとデフォルトで/usr/local/bin/配下にコピーされる。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ /usr/local/bin/event_rpcgen.py simple.rpc<br />
<br />
Reading &quot;./simple.rpc&quot;<br />
&nbsp; Created struct: GetUserRequest<br />
&nbsp; &nbsp; Added entry: id<br />
&nbsp; Created struct: GetUserResponse<br />
&nbsp; &nbsp; Added entry: errcode<br />
&nbsp; &nbsp; Added entry: name<br />
&nbsp; &nbsp; Added entry: email<br />
... creating &quot;./simple.gen.h&quot;<br />
... creating &quot;./simple.gen.c&quot;</div></div>
<p><a href="http://github.com/yokawasa/any/blob/master/libevent_rpc/simple.gen.h">simple.gen.h</a>と<a href="http://github.com/yokawasa/any/blob/master/libevent_rpc/simple.gen.c">simple.gen.c</a>の2つのファイルがジェネレートされる。 C/S両方でこのデータ構造を使用する。</p>
<p><h2><strong>RPCサーバの実装 &#8211; simple_rpc_server.cpp</strong></h2>
<p><a href="http://github.com/yokawasa/any/blob/master/libevent_rpc/simple_rpc_server.cpp">http://github.com/yokawasa/any/blob/master/libevent_rpc/simple_rpc_server.cpp</a></p>
<p>まずは利用するRPCメソッドの登録を行う。 <a href="http://www.monkey.org/~provos/libevent/doxygen-1.4.10/evrpc_8h.html#a526799df545537b2dc67358b0dfaa15">EVRPC_HEADER</a>でRPCコマンドのデータ構造とプロトタイプを作成して<a href="http://www.monkey.org/~provos/libevent/doxygen-1.4.10/evrpc_8h.html#f7abcafae087e3c4dce6a4cd85346114">EVRPC＿GENERATE</a>でRPCメッセージを送受信するためのコードを作成する。</p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339933;">#ifdef __cplusplus</span><br />
<span style="color: #000000; font-weight: bold;">extern</span> <span style="color: #ff0000;">&quot;C&quot;</span> <span style="color: #009900;">&#123;</span><br />
<span style="color: #339933;">#endif</span><br />
<span style="color: #339933;">#include &quot;simple.gen.h&quot;</span><br />
<span style="color: #339933;">#ifdef __cplusplus</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #339933;">#endif</span><br />
<span style="color: #339933;">#include &quot;evrpc.h&quot;</span><br />
&nbsp; &nbsp; <br />
<span style="color: #808080; font-style: italic;">/* registe RPC : GetUser */</span><br />
EVRPC_HEADER<span style="color: #009900;">&#40;</span>GetUser<span style="color: #339933;">,</span> GetUserRequest<span style="color: #339933;">,</span> GetUserResponse<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #808080; font-style: italic;">/* generate RPC code : GetUser */</span><br />
EVRPC_GENERATE<span style="color: #009900;">&#40;</span>GetUser<span style="color: #339933;">,</span> GetUserRequest<span style="color: #339933;">,</span> GetUserResponse<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>RPCサーバの実装について説明する。実装は既に存在するHTTPサーバの実装をベースとする。RPCサーバの基本コードは以下の通り。</p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> argc<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> <span style="color: #339933;">**</span>argv<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>argc <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">3</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.opengroup.org/onlinepubs/009695399/functions/fprintf.html"><span style="color: #000066;">fprintf</span></a><span style="color: #009900;">&#40;</span>stdout<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;%s &lt;server&gt; &lt;port&gt;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> argv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>svr_addr <span style="color: #339933;">=</span> argv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">short</span> svr_port <span style="color: #339933;">=</span> <a href="http://www.opengroup.org/onlinepubs/009695399/functions/atoi.html"><span style="color: #000066;">atoi</span></a><span style="color: #009900;">&#40;</span>argv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> evhttp <span style="color: #339933;">*</span>ev_http <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> evrpc_base <span style="color: #339933;">*</span>rpc_base <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* initialize base event mechanism */</span><br />
&nbsp; &nbsp; event_init<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; ev_http <span style="color: #339933;">=</span> evhttp_start<span style="color: #009900;">&#40;</span>svr_addr<span style="color: #339933;">,</span> svr_port<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* create a base for the RPC protocol */</span><br />
&nbsp; &nbsp; rpc_base <span style="color: #339933;">=</span> evrpc_init<span style="color: #009900;">&#40;</span>ev_http<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* register all of the handlers for all RPCs */</span><br />
&nbsp; &nbsp; EVRPC_REGISTER<span style="color: #009900;">&#40;</span>rpc_base<span style="color: #339933;">,</span> GetUser<span style="color: #339933;">,</span> GetUserRequest<span style="color: #339933;">,</span> GetUserResponse<span style="color: #339933;">,</span> GetUserCallback<span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* loop and dispatch events */</span><br />
&nbsp; &nbsp; event_dispatch<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; EVRPC_UNREGISTER<span style="color: #009900;">&#40;</span>rpc_base<span style="color: #339933;">,</span> GetUser<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; evrpc_free<span style="color: #009900;">&#40;</span>rpc_base<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; evhttp_free<span style="color: #009900;">&#40;</span>ev_http<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<ul>
<li>event_init()でlibeventライブラリ初期化。とりあえずlibeventを使う際は最初に一度実行しておく。</li>
<li>evhttp_start(svr_addr, svr_port)にサーバアドレス、ポートを指定してHTTPサーバ処理開始準備。</li>
<li>evrpc_init()でrpc処理ハンドル用ポインタを作成。</li>
<li><a href="http://www.monkey.org/~provos/libevent/doxygen-1.4.10/evrpc_8h.html#bb204281e2555a1e91ff3885747d0533">EVRPC_REGISTER</a>で特定のRPCコマンドをサーバに登録する。ここではさきほどEVRPC_HEADERとEVRPC_GENERATEで登録されたRPCコマンドGetUser（リクエスト用データ構造GetUserRequest, レスポンス用データ構造GetUserResponse）をRPCサーバに登録する。また同時にGetUserCallbackというRPCリクエストを受け取った際に呼び出されるコールバック関数を登録する。GetUserCallbackは次で説明する。</li>
<li>event_dispatch()でloop開始しイベントdispatchを開始する。</li>
<li>後処理。サーバ処理を終えるときEVRPC_UNREGISTER、evrpc_free, evhttp_freeの順で後処理をする。</li>
</ul>
<p><p>
GetUserCallbackはさきほどEVRPC_REGISTERでサーバに登録されたRPCコマンドのコールバック関数。 RPCクライアントから送信されるリクエストデータからidを取得。そのidに対するnameとemailデータをレスポンスデータにセットしている。</p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">static</span> <span style="color: #993333;">void</span><br />
GetUserCallback<span style="color: #009900;">&#40;</span>EVRPC_STRUCT<span style="color: #009900;">&#40;</span>GetUser<span style="color: #009900;">&#41;</span><span style="color: #339933;">*</span> rpc<span style="color: #339933;">,</span> <span style="color: #993333;">void</span> <span style="color: #339933;">*</span>arg<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> GetUserRequest<span style="color: #339933;">*</span> req <span style="color: #339933;">=</span> rpc<span style="color: #339933;">-&gt;</span>request<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> GetUserResponse<span style="color: #339933;">*</span> res <span style="color: #339933;">=</span> rpc<span style="color: #339933;">-&gt;</span>reply<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* get request info */</span><br />
&nbsp; &nbsp; <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>id<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>EVTAG_HAS<span style="color: #009900;">&#40;</span>req<span style="color: #339933;">,</span> id<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.opengroup.org/onlinepubs/009695399/functions/fprintf.html"><span style="color: #000066;">fprintf</span></a><span style="color: #009900;">&#40;</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;failed to get request info<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; EVTAG_ASSIGN<span style="color: #009900;">&#40;</span>res<span style="color: #339933;">,</span> errcode<span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; EVTAG_GET<span style="color: #009900;">&#40;</span>req<span style="color: #339933;">,</span> id<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>id<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <a href="http://www.opengroup.org/onlinepubs/009695399/functions/fprintf.html"><span style="color: #000066;">fprintf</span></a><span style="color: #009900;">&#40;</span>stdout<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;REQUEST id = %s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> id<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* do somthing due to request info */</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* set response info */</span><br />
&nbsp; &nbsp; EVTAG_ASSIGN<span style="color: #009900;">&#40;</span>res<span style="color: #339933;">,</span> errcode<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; EVTAG_ASSIGN<span style="color: #009900;">&#40;</span>res<span style="color: #339933;">,</span> name<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Fooo Baaar&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; EVTAG_ASSIGN<span style="color: #009900;">&#40;</span>res<span style="color: #339933;">,</span> email<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;baz@foo.bar&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* send the reply to the RPC */</span><br />
&nbsp; &nbsp; EVRPC_REQUEST_DONE<span style="color: #009900;">&#40;</span>rpc<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<ul>
<li>EVTAG_HASでリクエストデータ構造中のあるフィールドにデータがセットされているかをチェック(ここではid)してEVTAG_GETで実際にそのフィールドデータを取得。</li>
<li>EVTAG_ASSIGNでレスポンスデータ構造のフィールド(ここではerrcode, name, email)にデータをセット。</li>
<li>EVRPC_REQUEST_DONEでレスポンス送信。</li>
</ul>
<p><h2><strong>RPCクライアントの実装 &#8211; simple_rpc_client.cpp</strong></h2>
<p><a href="http://github.com/yokawasa/any/blob/master/libevent_rpc/simple_rpc_client.cpp">http://github.com/yokawasa/any/blob/master/libevent_rpc/simple_rpc_client.cpp<br />
</a><br />
RPCクライアントの実装について説明する。RPCクライアントでもサーバと同じようにEVRPC_HEADERとEVRPC＿GENERATEとで利用するRPCメソッドの登録を行う。以下RPCクライアントの基本コード。</p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> argc<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> <span style="color: #339933;">**</span>argv<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>argc <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">3</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.opengroup.org/onlinepubs/009695399/functions/fprintf.html"><span style="color: #000066;">fprintf</span></a><span style="color: #009900;">&#40;</span>stdout<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;%s &lt;server&gt; &lt;port&gt;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> argv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>svr_addr <span style="color: #339933;">=</span> argv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">short</span> svr_port <span style="color: #339933;">=</span> <a href="http://www.opengroup.org/onlinepubs/009695399/functions/atoi.html"><span style="color: #000066;">atoi</span></a><span style="color: #009900;">&#40;</span>argv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> event_base <span style="color: #339933;">*</span>ev_base <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> evhttp <span style="color: #339933;">*</span>ev_http <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> evrpc_base <span style="color: #339933;">*</span>rpc_base <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> evrpc_pool <span style="color: #339933;">*</span>rpc_pool <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> GetUserRequest <span style="color: #339933;">*</span>req<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> GetUserResponse <span style="color: #339933;">*</span>res<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* initialize base event mechanism */</span><br />
&nbsp; &nbsp; ev_base <span style="color: #339933;">=</span> event_init<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* initialize http internal buffer */</span><br />
&nbsp; &nbsp; ev_http <span style="color: #339933;">=</span> evhttp_new<span style="color: #009900;">&#40;</span>ev_base<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* create a base for the RPC protocol */</span><br />
&nbsp; &nbsp; rpc_base <span style="color: #339933;">=</span> evrpc_init<span style="color: #009900;">&#40;</span>ev_http<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; rpc_pool <span style="color: #339933;">=</span> get_rpc_pool<span style="color: #009900;">&#40;</span>ev_base<span style="color: #339933;">,</span> svr_addr<span style="color: #339933;">,</span> svr_port<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>rpc_pool<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* set up request data */</span><br />
&nbsp; &nbsp; req <span style="color: #339933;">=</span> GetUserRequest_new<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; EVTAG_ASSIGN<span style="color: #009900;">&#40;</span>req<span style="color: #339933;">,</span> id<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;foobar&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* create a response structure */</span><br />
&nbsp; &nbsp; res <span style="color: #339933;">=</span> GetUserResponse_new<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* set request, response, callback func */</span><br />
&nbsp; &nbsp; EVRPC_MAKE_REQUEST<span style="color: #009900;">&#40;</span>GetUser<span style="color: #339933;">,</span> rpc_pool<span style="color: #339933;">,</span> req<span style="color: #339933;">,</span> res<span style="color: #339933;">,</span> GetUserCallback<span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* process request and response */</span><br />
&nbsp; &nbsp; event_dispatch<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; GetUserRequest_free<span style="color: #009900;">&#40;</span>req<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; GetUserResponse_free<span style="color: #009900;">&#40;</span>res<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; evrpc_pool_free<span style="color: #009900;">&#40;</span>rpc_pool<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; evrpc_free<span style="color: #009900;">&#40;</span>rpc_base<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; evhttp_free<span style="color: #009900;">&#40;</span>ev_http<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<ul>
<li>event_init()でlibeventライブラリ初期化。</li>
<li>evhttp_new()でhttp処理用内部バッファーを初期化。</li>
<li>evrpc_init()でrpc処理ハンドル用ポインタを作成。</li>
<li>get_rpc_pool()よりevrpc_poolポインタを取得。get_rpc_pool()は次で説明。 evrpc_poolは内部にリクエストとして送信するための接続ポインタ(evhttp_connection)を持っている。</li>
<li>GetUserRequest_new()とGetUserResponse_new()によりRPCリクエストとレスポンスのためのリソース確保。</li>
<li>EVTAG_ASSIGNによりリクエスト用データ構造のidフィールドに値(&#8220;foobar&#8221;)を設定。</li>
<li><a href="http://www.monkey.org/~provos/libevent/doxygen-1.4.10/evrpc_8h.html#ff0efcd7cb8b966256b5127960bd2c81">EVRPC_MAKE_REQUEST</a>でサーバへのリクエスト送信に使うRPCコマンドとリクエスト、レスポンスオブジェクトポインタ、evrpc_poolポインタ、コールバック関数をセットする。コールバック関数GetUserCallbackは後で説明する。</li>
<li>event_dispatch()を呼んで実際にリクエスト送信、レスポンス受信を行う。</li>
<li>後処理。GetUserRequest_free()、GetUserResponse_free()でそれぞれリクエストとレスポンスのために確保されたリソースを開放。 次にevrpc_pool_free、evrpc_free, evhttp_freeの順で後処理実行。</li>
</ul>
<p><p>
RPCリクエスト処理で使用するevrpc_poolポインタを取得するための関数。get_rpc_poolがコールされる度にサーバ接続ポインタ (evhttp_connection)を生成しevrpc_poolの接続プールに追加している。 ちなみにevrpc_poolとはいわゆるコネクションプールのこと。仕組みとしては内部に接続とリクエストを管理するQUEUEを持っていてリクエストごとに接続QUEUEから空いている接続をリクエストに割り当てる。もし割り当てる接続がなければそのリクエストをリクエストQUEUEに追加する。</p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">static</span> <span style="color: #993333;">struct</span> evrpc_pool <span style="color: #339933;">*</span><br />
&nbsp;get_rpc_pool<span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> event_base <span style="color: #339933;">*</span>base<span style="color: #339933;">,</span> <span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>svr_addr<span style="color: #339933;">,</span> <span style="color: #993333;">short</span> svr_port<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> evhttp_connection <span style="color: #339933;">*</span>ev_conn<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> evrpc_pool <span style="color: #339933;">*</span>rpc_pool<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; rpc_pool <span style="color: #339933;">=</span> evrpc_pool_new<span style="color: #009900;">&#40;</span>base<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>rpc_pool<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.opengroup.org/onlinepubs/009695399/functions/fprintf.html"><span style="color: #000066;">fprintf</span></a><span style="color: #009900;">&#40;</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;failed to get new rpc pool<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> NULL<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// create a connection to RPC server</span><br />
&nbsp; &nbsp; ev_conn <span style="color: #339933;">=</span> evhttp_connection_new<span style="color: #009900;">&#40;</span>svr_addr<span style="color: #339933;">,</span> svr_port<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>ev_conn<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.opengroup.org/onlinepubs/009695399/functions/fprintf.html"><span style="color: #000066;">fprintf</span></a><span style="color: #009900;">&#40;</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;failed to get new evhttp connection: %s:%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; svr_addr<span style="color: #339933;">,</span> svr_port<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> NULL<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// add request connection in the pool</span><br />
&nbsp; &nbsp; evrpc_pool_add_connection<span style="color: #009900;">&#40;</span>rpc_pool<span style="color: #339933;">,</span> ev_conn<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #009900;">&#40;</span>rpc_pool<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<ul>
<li>evrpc_pool_new()でrpcコネクションプールを作成。</li>
<li>evhttp_connection_newでリクエスト用接続ポインタを生成。</li>
<li>evrpc_pool_add_connectionでevrpc_poolの接続プールに生成されたリクエスト用接続ポインタを追加。</li>
</ul>
<p><p>
以下EVRPC_MAKE_REQUESTで指定するRPCリクエストを送信してサーバよりレスポンスが返ってきたときに呼ばれるコールバック関数。RPC クライアントからのリクエストに対するサーバからのレスポンス結果を表示している。</p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">static</span> <span style="color: #993333;">void</span><br />
&nbsp;GetUserCallback<span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> evrpc_status <span style="color: #339933;">*</span>status<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> GetUserRequest <span style="color: #339933;">*</span>req<span style="color: #339933;">,</span> <span style="color: #993333;">struct</span> GetUserResponse <span style="color: #339933;">*</span>res<span style="color: #339933;">,</span> <span style="color: #993333;">void</span> <span style="color: #339933;">*</span>arg<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">uint32_t</span> errcode<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>name<span style="color: #339933;">,*</span>email<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* check return status */</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>status<span style="color: #339933;">-&gt;</span>error <span style="color: #339933;">!=</span> EVRPC_STATUS_ERR_NONE<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">goto</span> exitloop<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* get response info */</span><br />
&nbsp; &nbsp; EVTAG_GET<span style="color: #009900;">&#40;</span>res<span style="color: #339933;">,</span> errcode<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>errcode<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <a href="http://www.opengroup.org/onlinepubs/009695399/functions/fprintf.html"><span style="color: #000066;">fprintf</span></a><span style="color: #009900;">&#40;</span>stdout<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;RESPONSE errcode=%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> errcode<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>EVTAG_HAS<span style="color: #009900;">&#40;</span>res<span style="color: #339933;">,</span> name<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; EVTAG_GET<span style="color: #009900;">&#40;</span>res<span style="color: #339933;">,</span> name<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>name<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.opengroup.org/onlinepubs/009695399/functions/fprintf.html"><span style="color: #000066;">fprintf</span></a><span style="color: #009900;">&#40;</span>stdout<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;RESPONSE name=%s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> name<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>EVTAG_HAS<span style="color: #009900;">&#40;</span>res<span style="color: #339933;">,</span> email<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; EVTAG_GET<span style="color: #009900;">&#40;</span>res<span style="color: #339933;">,</span> email<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>email<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.opengroup.org/onlinepubs/009695399/functions/fprintf.html"><span style="color: #000066;">fprintf</span></a><span style="color: #009900;">&#40;</span>stdout<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;RESPONSE email=%s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> email<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
exitloop<span style="color: #339933;">:</span><br />
&nbsp; &nbsp; event_loopexit<span style="color: #009900;">&#40;</span>NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>
<h2><strong>ダウンロード、コンパイル、動作確認</strong></h2>
<p>git clone でソースコードを取得してmakeを行う。 リポジトリanyのサブディレクトリ any/libevent_rpcが今回のサンプルにあたる。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ git clone git@github.com:yokawasa/any.git &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
<br />
Initialized empty Git repository in /home/m/dev/github/any/.git/<br />
remote: Counting objects: 33, done.<br />
remote: Compressing objects: 100% (32/32), done.<br />
remote: Total 33 (delta 7), reused 0 (delta 0)<br />
Receiving objects: 100% (33/33), 11.28 KiB, done.<br />
Resolving deltas: 100% (7/7), done.<br />
<br />
$ cd any/libevent_rpc<br />
$ make<br />
<br />
g++ -I/usr/include -I/usr/local/include -Wall -g -o simple_rpc_client.o -c simple_rpc_client.cpp<br />
gcc -I/usr/include -I/usr/local/include -Wall -g -o simple.gen.o -c simple.gen.c<br />
g++ -L/usr/local/lib -levent -o simple_rpc_client simple_rpc_client.o simple.gen.o<br />
g++ -I/usr/include -I/usr/local/include -Wall -g -o simple_rpc_server.o -c simple_rpc_server.cpp<br />
g++ -L/usr/local/lib -levent -o simple_rpc_server simple_rpc_server.o simple.gen.o</div></div>
<p>これで同ディレクトリにRPCサーバsimple_rpc_server とRPCクライアントsimple_rpc_client実行ファイルのできあがり。simple_rpc_server 、simple_rpc_clientともに実行時に第一引数にサーバアドレス、第二引数にIOポートを指定する。 まずサーバから立ち上げる。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ ./simple_rpc_server localhost 8888</div></div>
<p>サーバが立ち上がったら次のようにクライアントからリクエスト送信する。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ ./simple_rpc_client localhost 8888<br />
RESPONSE errcode=0<br />
RESPONSE name=Fooo Baaar<br />
RESPONSE email=baz@foo.bar</div></div>
<p>上のような結果が出力されればOK。</p>
<p>おわり。</p>
<iframe src="http://www.facebook.com/plugins/like.php?href=http://yk55.com/blog/2010/06/05/libevent_rpc_cs_programmin/&amp;layout=button_count&amp;show_faces=1&amp;width=450&amp;action=like&amp;colorscheme=light&amp;font=arial" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:25px"></iframe>]]></content:encoded>
			<wfw:commentRss>http://yk55.com/blog/2010/06/05/libevent_rpc_cs_programmin/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>LibeventとAPRでイベント駆動型HTTPサーバを作成してみた</title>
		<link>http://yk55.com/blog/2010/04/30/eventdriven_http_server_vs_httpd/</link>
		<comments>http://yk55.com/blog/2010/04/30/eventdriven_http_server_vs_httpd/#comments</comments>
		<pubDate>Fri, 30 Apr 2010 01:35:25 +0000</pubDate>
		<dc:creator>yoichi</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[ab]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[apr]]></category>
		<category><![CDATA[c]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[libevent]]></category>
		<category><![CDATA[memorypool]]></category>
		<category><![CDATA[network]]></category>
		<category><![CDATA[vs_httpd]]></category>

		<guid isPermaLink="false">http://yk55.com/blog/?p=319</guid>
		<description><![CDATA[イベント駆動型処理フレームワークの定番？であるlibevent(An event notification library)とAPR(Apache ProtableRuntime)を使ってイベント駆動型HTTPサーバを書いてみた。既にこの手の簡易HTTPサーバは書き尽くされてる感があり何ら目新しさはなく、若干車輪の再開発的なものになってしまっているのは否めないがそこは気にしないでlibeventが提供するイベント駆動型HTTP処理機能（evhttp）のサンプルの1つとして読んでいただきたく。ちなみにAPRは主にメモリプールのために使っている。 ソースコード &#8211; vs_httpd.c http://github.com/yokawasa/vs_httpd/ http://github.com/yokawasa/vs_httpd/blob/master/vs_httpd.c イベント駆動HTTP処理基本コード main @ vs_httpd.c struct evhttp *httpd; /* event driven http */ event_init&#40;&#41;; httpd = evhttp_start&#40;g_config-&#62;svr_addr, g_config-&#62;svr_port&#41;; evhttp_set_gencb&#40;httpd, main_request_handler, NULL&#41;; event_dispatch&#40;&#41;; evhttp_free&#40;httpd&#41;; event_initでlibeventライブラリの初期化処理。event_base_new()でもOK evhttp_start(address, port)でbindするアドレス、listenするポートを指定 evhttp_set_gencbでリクエストイベントが通知される度にコールされるコールバック関数(main_request_handler)を登録。 event_dispatchでイベントループを開始しイベント通知を開始 evhttp_freeで作成されたHTTPサーバリソースを開放 &#91;evhttp_set_gencbの定義 @ evhttp.h&#93; /** Set a callback for all requests that are not caught by specific callbacks [...]]]></description>
			<content:encoded><![CDATA[<p>イベント駆動型処理フレームワークの定番？である<a href="http://monkey.org/~provos/libevent/">libevent</a>(An event notification library)と<a href="http://apr.apache.org/">APR</a>(Apache ProtableRuntime)を使ってイベント駆動型HTTPサーバを書いてみた。既にこの手の簡易HTTPサーバは書き尽くされてる感があり何ら目新しさはなく、若干車輪の再開発的なものになってしまっているのは否めないがそこは気にしないでlibeventが提供するイベント駆動型HTTP処理機能（<strong>evhttp</strong>）のサンプルの1つとして読んでいただきたく。ちなみにAPRは主にメモリプールのために使っている。</p>
<p><h2><strong>ソースコード &#8211; vs_httpd.c</strong></h2>
<p><a href="http://github.com/yokawasa/vs_httpd/">http://github.com/yokawasa/vs_httpd/</a><br />
<a href="http://github.com/yokawasa/vs_httpd/blob/master/vs_httpd.c">http://github.com/yokawasa/vs_httpd/blob/master/vs_httpd.c</a></p>
<p><u>イベント駆動HTTP処理基本コード  main @ vs_httpd.c</u></p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">struct</span> evhttp <span style="color: #339933;">*</span>httpd<span style="color: #339933;">;</span><br />
<br />
<span style="color: #808080; font-style: italic;">/* event driven http */</span><br />
event_init<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
httpd <span style="color: #339933;">=</span> evhttp_start<span style="color: #009900;">&#40;</span>g_config<span style="color: #339933;">-&gt;</span>svr_addr<span style="color: #339933;">,</span> g_config<span style="color: #339933;">-&gt;</span>svr_port<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
evhttp_set_gencb<span style="color: #009900;">&#40;</span>httpd<span style="color: #339933;">,</span> main_request_handler<span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
event_dispatch<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
evhttp_free<span style="color: #009900;">&#40;</span>httpd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<ul>
<li>event_initでlibeventライブラリの初期化処理。event_base_new()でもOK</li>
<li>evhttp_start(address, port)でbindするアドレス、listenするポートを指定</li>
<li>evhttp_set_gencbでリクエストイベントが通知される度にコールされるコールバック関数(main_request_handler)を登録。</li>
<li>event_dispatchでイベントループを開始しイベント通知を開始</li>
<li>evhttp_freeで作成されたHTTPサーバリソースを開放</li>
</ul>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&#91;</span>evhttp_set_gencbの定義 @ evhttp.<span style="color: #202020;">h</span><span style="color: #009900;">&#93;</span><br />
<span style="color: #808080; font-style: italic;">/** Set a callback for all requests that are not caught by specific callbacks */</span><br />
<span style="color: #993333;">void</span> evhttp_set_gencb<span style="color: #009900;">&#40;</span> <span style="color: #993333;">struct</span> evhttp <span style="color: #339933;">*,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333;">void</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> evhttp_request <span style="color: #339933;">*,</span> <span style="color: #993333;">void</span> <span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #993333;">void</span> <span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p><p>
<u>リクエスト処理用コールバック関数 main_request_handler @ vs_httpd.c</u></p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">void</span> main_request_handler<span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> evhttp_request <span style="color: #339933;">*</span>r<span style="color: #339933;">,</span> <span style="color: #993333;">void</span> <span style="color: #339933;">*</span>args<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; apr_status_t rv<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> evbuffer <span style="color: #339933;">*</span>evbuf<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>path<span style="color: #339933;">,</span> <span style="color: #339933;">*</span>mimetype<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>complemented_path<span style="color: #339933;">,</span> <span style="color: #339933;">*</span>extbuf<span style="color: #339933;">,</span> <span style="color: #339933;">*</span>filebuf<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">int</span> filesize <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* check reqeust type. currently only suppoert GET */</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>r<span style="color: #339933;">-&gt;</span>type <span style="color: #339933;">!=</span> EVHTTP_REQ_GET<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.opengroup.org/onlinepubs/009695399/functions/fprintf.html"><span style="color: #000066;">fprintf</span></a><span style="color: #009900;">&#40;</span>stdout<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;only support GET request <span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; evhttp_send_error<span style="color: #009900;">&#40;</span>r<span style="color: #339933;">,</span> HTTP_BADREQUEST<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;only support GET request&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; path <span style="color: #339933;">=</span> apr_psprintf<span style="color: #009900;">&#40;</span>g_mem_pool<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;%s%s&quot;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; g_config<span style="color: #339933;">-&gt;</span>doc_root<span style="color: #339933;">,</span> evhttp_request_uri<span style="color: #009900;">&#40;</span>r<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>g_config<span style="color: #339933;">-&gt;</span>verbose<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.opengroup.org/onlinepubs/009695399/functions/fprintf.html"><span style="color: #000066;">fprintf</span></a><span style="color: #009900;">&#40;</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;req uri=%s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> evhttp_request_uri<span style="color: #009900;">&#40;</span>r<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.opengroup.org/onlinepubs/009695399/functions/fprintf.html"><span style="color: #000066;">fprintf</span></a><span style="color: #009900;">&#40;</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;req path=%s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> path <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* file or dir existence check */</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>exists<span style="color: #009900;">&#40;</span>path<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>complemented_path<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>filesize<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; evhttp_send_error<span style="color: #009900;">&#40;</span>r<span style="color: #339933;">,</span> HTTP_NOTFOUND<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;file not found&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* file's extension check */</span><br />
&nbsp; &nbsp; mimetype <span style="color: #339933;">=</span> apr_pstrdup<span style="color: #009900;">&#40;</span>g_mem_pool<span style="color: #339933;">,</span> DEFAULT_MIME_TYPE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; extbuf <span style="color: #339933;">=</span> <a href="http://www.opengroup.org/onlinepubs/009695399/functions/strrchr.html"><span style="color: #000066;">strrchr</span></a><span style="color: #009900;">&#40;</span>complemented_path<span style="color: #339933;">,</span><span style="color: #ff0000;">'.'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>extbuf<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #339933;">++</span>extbuf<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; mimetype <span style="color: #339933;">=</span> find_mime_type<span style="color: #009900;">&#40;</span>extbuf<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* file read */</span><br />
&nbsp; &nbsp; filebuf <span style="color: #339933;">=</span> apr_palloc<span style="color: #009900;">&#40;</span>g_mem_pool<span style="color: #339933;">,</span> filesize <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; apr_file_t <span style="color: #339933;">*</span>file <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; rv <span style="color: #339933;">=</span> apr_file_open<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>file<span style="color: #339933;">,</span> complemented_path<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;APR_READ<span style="color: #339933;">|</span>APR_BINARY<span style="color: #339933;">,</span> APR_OS_DEFAULT<span style="color: #339933;">,</span> g_mem_pool<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>rv <span style="color: #339933;">!=</span> APR_SUCCESS<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; evhttp_send_error<span style="color: #009900;">&#40;</span>r<span style="color: #339933;">,</span> HTTP_SERVUNAVAIL<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;failed to open file&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; apr_size_t len <span style="color: #339933;">=</span> filesize<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; rv <span style="color: #339933;">=</span> apr_file_read<span style="color: #009900;">&#40;</span>file<span style="color: #339933;">,</span> filebuf<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>len<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>rv <span style="color: #339933;">!=</span> APR_SUCCESS<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; evhttp_send_error<span style="color: #009900;">&#40;</span>r<span style="color: #339933;">,</span> HTTP_SERVUNAVAIL<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;failed to read file&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; apr_file_close<span style="color: #009900;">&#40;</span>file<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp;<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>g_config<span style="color: #339933;">-&gt;</span>verbose<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.opengroup.org/onlinepubs/009695399/functions/fprintf.html"><span style="color: #000066;">fprintf</span></a><span style="color: #009900;">&#40;</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;res mimetype=%s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> mimetype<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.opengroup.org/onlinepubs/009695399/functions/fprintf.html"><span style="color: #000066;">fprintf</span></a><span style="color: #009900;">&#40;</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;res file size=%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> len<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.opengroup.org/onlinepubs/009695399/functions/fprintf.html"><span style="color: #000066;">fprintf</span></a><span style="color: #009900;">&#40;</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;res file output=%s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> filebuf<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; evbuf <span style="color: #339933;">=</span> evbuffer_new<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>evbuf<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.opengroup.org/onlinepubs/009695399/functions/fprintf.html"><span style="color: #000066;">fprintf</span></a><span style="color: #009900;">&#40;</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;failed to create response buffer<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; evhttp_send_error<span style="color: #009900;">&#40;</span>r<span style="color: #339933;">,</span> HTTP_SERVUNAVAIL<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;failed to create response buffer&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; evhttp_add_header<span style="color: #009900;">&#40;</span>r<span style="color: #339933;">-&gt;</span>output_headers<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Content-Type&quot;</span><span style="color: #339933;">,</span>mimetype<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; evhttp_add_header<span style="color: #009900;">&#40;</span>r<span style="color: #339933;">-&gt;</span>output_headers<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Content-Length&quot;</span><span style="color: #339933;">,</span> apr_psprintf<span style="color: #009900;">&#40;</span>g_mem_pool<span style="color: #339933;">,</span><span style="color: #ff0000;">&quot;%d&quot;</span><span style="color: #339933;">,</span>filesize<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; evbuffer_add<span style="color: #009900;">&#40;</span>evbuf<span style="color: #339933;">,</span> filebuf<span style="color: #339933;">,</span> len<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; evhttp_send_reply<span style="color: #009900;">&#40;</span>r<span style="color: #339933;">,</span> HTTP_OK<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;&quot;</span><span style="color: #339933;">,</span> evbuf<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; evbuffer_free<span style="color: #009900;">&#40;</span>evbuf<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<ul>
<li>GETメソッド(EVHTTP_REQ_GET)のみ処理を行う</li>
<li>exists()でリクエストされたuri(evhttp_request_uri(r))がファイルまたはディレクトリとして存在するかをチェック</li>
<li>find_mime_typeでファイル拡張子に対応するMIME TYPEを取得。拡張子がなければデフォルトMIME TYPE application/ocet-stream。この部分の処理は600 行のCでCGIをサポートする軽量WEBサーバ<a href="http://www.ibm.com/developerworks/jp/web/library/wa-ltwebserv/">mattows</a>のコードを参考、流用。</li>
<li>APRの<a href="http://apr.apache.org/docs/apr/1.4/group__apr__file__io.html">ファイルI/Oハンドルライブラリ</a>でファイルの読み込み。画像等バイナリファイルのためにopen時にAPR_BINARYフラグを指定している</li>
<li>evhttp_add_headerでレスポンス用outputヘッダに&#8221;Content-Type&#8221;と&#8221;Content-Lenght&#8221;を指定</li>
<li>(struct evbuffe*)evbufに読み込んだファイルデータをボディデータとして書き込む</li>
<li>evhttp_send_replyでクライアントにレスポンス</li>
</ul>
<p><p>
<u>APRメモリプールの利用 @ vs_httpd.c</u><br />
これは本題からそれるが全体的な特徴としてメモリ管理はAPRの<a href="http://apr.apache.org/docs/apr/1.4/group__apr__pools.html">メモリプール</a>を利用しているのでここで軽く説明する。</p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">static</span> apr_pool_t <span style="color: #339933;">*</span>g_mem_pool <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span><br />
apr_pool_create<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>g_mem_pool<span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
...<br />
<span style="color: #202020;">g_config</span> <span style="color: #339933;">=</span> apr_pcalloc<span style="color: #009900;">&#40;</span>g_mem_pool<span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>httpsvr_config<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
path <span style="color: #339933;">=</span> apr_psprintf<span style="color: #009900;">&#40;</span>g_mem_pool<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;%s%s&quot;</span><span style="color: #339933;">,</span> g_config<span style="color: #339933;">-&gt;</span>doc_root<span style="color: #339933;">,</span> evhttp_request_uri<span style="color: #009900;">&#40;</span>r<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
mimetype <span style="color: #339933;">=</span> apr_pstrdup<span style="color: #009900;">&#40;</span>g_mem_pool<span style="color: #339933;">,</span> DEFAULT_MIME_TYPE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
filebuf <span style="color: #339933;">=</span> apr_palloc<span style="color: #009900;">&#40;</span>g_mem_pool<span style="color: #339933;">,</span> filesize <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
rv <span style="color: #339933;">=</span> apr_file_open<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>file<span style="color: #339933;">,</span> complemented_path<span style="color: #339933;">,</span> APR_READ<span style="color: #339933;">|</span>APR_BINARY<span style="color: #339933;">,</span> APR_OS_DEFAULT<span style="color: #339933;">,</span> g_mem_pool<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
...<br />
<span style="color: #202020;">apr_pool_destroy</span><span style="color: #009900;">&#40;</span>g_mem_pool<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<ul>
<li>apr_pool_createでメモリプールの作成 </li>
<li>apr_palloc、apr_psprintf, を使用して、メモリプールからメモリを確保します</li>
<li>apr_pool_destroyを使用して、メモリプールを破棄 </li>
</ul>
<p><h2><strong>ダウンロード、コンパイル、そしてテスト</strong></h2>
<p>git clone で<a href="http://github.com/yokawasa/vs_httpd/">vs_httpdのコード</a>を取得(リポジトリ複製)する。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ git clone git@github.com:yokawasa/vs_httpd.git<br />
<br />
Initialized empty Git repository in /home/m/dev/github/t/vs_httpd/.git/<br />
remote: Counting objects: 11, done.<br />
remote: Compressing objects: 100% (11/11), done.<br />
remote: Total 11 (delta 0), reused 0 (delta 0)<br />
Receiving objects: 100% (11/11), 8.51 KiB, done.</div></div>
<p>libeventとaprヘッダへのインクルードや両ライブラリのリンクができるようにMakefileのパス調整を行う。もちろんlibeventとaprがインストール済みであることが前提。もしまだならばまずはlibeventとaprをインストールしましょ。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ vi Makefile<br />
CFLAGS = -I&lt;libeventのincludeパス&gt; -I&lt;apacheのincludeパス -Wall -g<br />
LIBS = -L&lt;libeventのlibパス&gt; -levent -L&lt;apacheのlibパス&gt; -lapr-1</div></div>
<p>パス変更後にmakeを実行。これでvs_httpdバイナリの出来上がり。vs_httpdの使い方は次のとおり。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ ./vs_httpd -h<br />
Usage: vs_httpd [-a address] [-p port] [-d documentroot]<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;[-D] [-v] [-h]<br />
Options:<br />
&nbsp; -a address &nbsp; &nbsp; &nbsp;: define server address (default: &quot;0.0.0.0&quot;)<br />
&nbsp; -p port &nbsp; &nbsp; &nbsp; &nbsp; : define server port (default: 8080)<br />
&nbsp; -d documentroot : define document root (default: &quot;./&quot;) &nbsp;<br />
&nbsp; -D &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;: daemonize option 0-off,1-on (default: 0)<br />
&nbsp; -v &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;: verbose option 0-off,1-on (default: 0)<br />
&nbsp; -h &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;: list available command line options (this page)</div></div>
<p>使い方の説明にあるようにオプションを指定しない場合はデフォルトサーバアドレス&#8221;0.0.0.0&#8243;、ポート番号 8080、ドキュメントルート &#8220;./&#8221;、デーモンモードOFF、VerboseモードOFFで起動される。尚、デフォルトインデックスファイルをindex.htmlとしているので http://hostname:port/path/のようにファイル名を指定しないでアクセスした場合はvs_httpdがドキュメントルート /path/配下のindex.htmlを表示させようとする。試しにvs_httpdをポート(8888)、ドキュメントルート(/home /vs_httpd/docs)、デーモンモードON、VerboseモードONで起動させてみる。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ ./vs_httpd -p 8888 -d /home/vs_httpd/docs -D -v<br />
svr_addr=0.0.0.0<br />
svr_port=8888<br />
doc_root=/home/vs_httpd/docs<br />
verbose=1<br />
daemonize=1<br />
$ ※<br />
<br />
※ daemonized! fork成功、親プロセスからはexitで子プロセスに処理が移る</div></div>
<p>ページ表示テスト用にvs_httpd/pages下にhtml、css、jpegファイルを用意してあるのでこれらを/home/vs_httpd /docs配下に配置して実際にブラウザでindex.htmlを表示させてみる。成功すると以下のようなページが表示させる。</p>
<p><a href="http://www.flickr.com/photos/yk55/4563326293/" title="VSHTTPD by yoichi*, on Flickr"><img src="http://farm4.static.flickr.com/3214/4563326293_63624d58f8_o.jpg" width="680" height="335" alt="VSHTTPD" /></a></p>
<p><h2><strong>ベンチマーク結果</strong></h2>
<p><a href="http://httpd.apache.org/docs/2.0/programs/ab.html">ab(apache bench)</a>でベンチマークテストをしてみる。並列数100、リクエスト数10000。比較のためにapache2(mpm prefork)でもテストをしてみる。まずはvs_httpdのテスト結果。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ ab -c 100 -n 10000 http://127.0.0.1:8888/<br />
<br />
Server Software: &nbsp; &nbsp; &nbsp; &nbsp;<br />
Server Hostname: &nbsp; &nbsp; &nbsp; &nbsp;127.0.0.1<br />
Server Port: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;8888<br />
<br />
Document Path: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;/<br />
Document Length: &nbsp; &nbsp; &nbsp; &nbsp;285 bytes<br />
<br />
Concurrency Level: &nbsp; &nbsp; &nbsp;100<br />
Time taken for tests: &nbsp; 2.295104 seconds<br />
Complete requests: &nbsp; &nbsp; &nbsp;10000<br />
Failed requests: &nbsp; &nbsp; &nbsp; &nbsp;0<br />
Write errors: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0<br />
Total transferred: &nbsp; &nbsp; &nbsp;3490440 bytes<br />
HTML transferred: &nbsp; &nbsp; &nbsp; 2858550 bytes<br />
Requests per second: &nbsp; &nbsp;4357.10 [#/sec] (mean)<br />
Time per request: &nbsp; &nbsp; &nbsp; 22.951 [ms] (mean)<br />
Time per request: &nbsp; &nbsp; &nbsp; 0.230 [ms] (mean, across all concurrent requests)<br />
Transfer rate: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1484.90 [Kbytes/sec] received<br />
<br />
Connection Times (ms)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; min &nbsp;mean[+/-sd] median &nbsp; max<br />
Connect: &nbsp; &nbsp; &nbsp; &nbsp;0 &nbsp; &nbsp;5 &nbsp; 4.2 &nbsp; &nbsp; &nbsp;4 &nbsp; &nbsp; &nbsp;27<br />
Processing: &nbsp; &nbsp; 5 &nbsp; 17 &nbsp; 6.4 &nbsp; &nbsp; 15 &nbsp; &nbsp; &nbsp;46<br />
Waiting: &nbsp; &nbsp; &nbsp; &nbsp;1 &nbsp; 13 &nbsp; 6.5 &nbsp; &nbsp; 11 &nbsp; &nbsp; &nbsp;45<br />
Total: &nbsp; &nbsp; &nbsp; &nbsp; 10 &nbsp; 22 &nbsp; 7.0 &nbsp; &nbsp; 21 &nbsp; &nbsp; &nbsp;47<br />
<br />
Percentage of the requests served within a certain time (ms)<br />
&nbsp; 50% &nbsp; &nbsp; 21<br />
&nbsp; 66% &nbsp; &nbsp; 24<br />
&nbsp; 75% &nbsp; &nbsp; 26<br />
&nbsp; 80% &nbsp; &nbsp; 27<br />
&nbsp; 90% &nbsp; &nbsp; 32<br />
&nbsp; 95% &nbsp; &nbsp; 37<br />
&nbsp; 98% &nbsp; &nbsp; 41<br />
&nbsp; 99% &nbsp; &nbsp; 42<br />
&nbsp;100% &nbsp; &nbsp; 47 (longest request)</div></div>
<p>次にapache2(mpm prefork)でも同様のテストを行う。利用するページはvs_httpdと同じでテスト環境のprefork MPM設定値は次のとおり。</p>
<pre>
[prefork MPMの設定値]
StartServers          5
MinSpareServers       5
MaxSpareServers      10
MaxClients          150
MaxRequestsPerChild   0
</pre>
<p>以下、apache2のテスト結果。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ ab -c 100 -n 10000 http://127.0.0.1/<br />
<br />
Server Software: &nbsp; &nbsp; &nbsp; &nbsp;Apache/2.2.2<br />
Server Hostname: &nbsp; &nbsp; &nbsp; &nbsp;127.0.0.1<br />
Server Port: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;80<br />
<br />
Document Path: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;/<br />
Document Length: &nbsp; &nbsp; &nbsp; &nbsp;285 bytes<br />
<br />
Concurrency Level: &nbsp; &nbsp; &nbsp;100<br />
Time taken for tests: &nbsp; 3.580232 seconds<br />
Complete requests: &nbsp; &nbsp; &nbsp;10000<br />
Failed requests: &nbsp; &nbsp; &nbsp; &nbsp;0<br />
Write errors: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0<br />
Total transferred: &nbsp; &nbsp; &nbsp;5310000 bytes<br />
HTML transferred: &nbsp; &nbsp; &nbsp; 2850000 bytes<br />
Requests per second: &nbsp; &nbsp;2793.12 [#/sec] (mean)<br />
Time per request: &nbsp; &nbsp; &nbsp; 35.802 [ms] (mean)<br />
Time per request: &nbsp; &nbsp; &nbsp; 0.358 [ms] (mean, across all concurrent requests)<br />
Transfer rate: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1448.23 [Kbytes/sec] received<br />
<br />
Connection Times (ms)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; min &nbsp;mean[+/-sd] median &nbsp; max<br />
Connect: &nbsp; &nbsp; &nbsp; &nbsp;0 &nbsp; &nbsp;0 &nbsp; 0.8 &nbsp; &nbsp; &nbsp;0 &nbsp; &nbsp; &nbsp;10<br />
Processing: &nbsp; &nbsp; 8 &nbsp; 35 &nbsp; 7.4 &nbsp; &nbsp; 31 &nbsp; &nbsp; &nbsp;66<br />
Waiting: &nbsp; &nbsp; &nbsp; &nbsp;2 &nbsp; 34 &nbsp; 7.4 &nbsp; &nbsp; 31 &nbsp; &nbsp; &nbsp;66<br />
Total: &nbsp; &nbsp; &nbsp; &nbsp; 12 &nbsp; 35 &nbsp; 7.4 &nbsp; &nbsp; 31 &nbsp; &nbsp; &nbsp;66<br />
<br />
Percentage of the requests served within a certain time (ms)<br />
&nbsp; 50% &nbsp; &nbsp; 31<br />
&nbsp; 66% &nbsp; &nbsp; 36<br />
&nbsp; 75% &nbsp; &nbsp; 40<br />
&nbsp; 80% &nbsp; &nbsp; 43<br />
&nbsp; 90% &nbsp; &nbsp; 47<br />
&nbsp; 95% &nbsp; &nbsp; 50<br />
&nbsp; 98% &nbsp; &nbsp; 53<br />
&nbsp; 99% &nbsp; &nbsp; 54<br />
&nbsp;100% &nbsp; &nbsp; 66 (longest request)</div></div>
<p>単純すぎるベンチマークテストなのでアレなのですが、10000リクエストの処理時間だけをみるとvs_httpd(2.295104 seconds)のほうがapache2(3.580232 seconds)よりも約35%速いといえる。余計な処理はな何も行わないで静的ファイル処理に特化しているので速いのは当たり前なんだけど、うれしい。この世界、速いは美徳。</p>
<p>おわり。</p>
<iframe src="http://www.facebook.com/plugins/like.php?href=http://yk55.com/blog/2010/04/30/eventdriven_http_server_vs_httpd/&amp;layout=button_count&amp;show_faces=1&amp;width=450&amp;action=like&amp;colorscheme=light&amp;font=arial" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:25px"></iframe>]]></content:encoded>
			<wfw:commentRss>http://yk55.com/blog/2010/04/30/eventdriven_http_server_vs_httpd/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>cURL MultiインターフェースでHTTP Pipeliningリクエストの送信</title>
		<link>http://yk55.com/blog/2010/04/20/curl_multi_http_pipelining_reques/</link>
		<comments>http://yk55.com/blog/2010/04/20/curl_multi_http_pipelining_reques/#comments</comments>
		<pubDate>Tue, 20 Apr 2010 14:54:54 +0000</pubDate>
		<dc:creator>yoichi</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[cplusplus]]></category>
		<category><![CDATA[curl]]></category>
		<category><![CDATA[debian]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[keep-alive]]></category>
		<category><![CDATA[network]]></category>
		<category><![CDATA[pipelining]]></category>
		<category><![CDATA[tcpdump]]></category>
		<category><![CDATA[tcpip]]></category>

		<guid isPermaLink="false">http://yk55.com/blog/?p=303</guid>
		<description><![CDATA[cURLのC APIマニュアルを読んでいたらCURLMOPT_PIPELININGというおもしろそうなオプションを見つけた。これはlibcurl 7.16.0 より加わった並列実行用Multiインターフェースのオプションで、設定することでHTTP Pipeliningなリクエストが送信できるようになる。HTTP Pipeliningとは個々のレスポンスを待つことなく複数のリクエストを投げることを意味するHTTP/1.1よりサポートされた通信パフォーマンス向上のためのテクニックである。 通常N個のリクエストを処理する際はN個ソケットがオープンされOPEN → REQUEST → RESPONSE → CLOSEなサイクルがN回行われる。Multiインターフェースによる並列処理の場合はOPEN → REQUEST → RESPONSE → CLOSEが並列に行われる。 またこれがkeep-aliveな接続であればOPEN → (REQUEST → RESPONSE) x N → CLOSEのようにクローズされるまで１ソケットが再利用される。 そしてHTTP Pipeliningはkeep-aliveな接続で使うテクニックであり、これが有効な場合は1ソケットオープン後にOPEN → (REQUEST x N) → (RESPONSE x N) → CLOSEのようにリクエストN個をレスポンスを待つことなく1ソケットに書き込むことができる。 まとめて送信される分パケット効率がアップし全体的なネットワークを流れるパケットの数を減らすことができ、 さらにまとめてリクエスト送信するので高レイテンシーなネットワークにおいては速度面で効果的といえる。 see also 「Mozilla HTTP/1.1 パイプライン化 FAQ」。 (1) NOT keep-alive, single &#160; &#160; &#160; [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://curl.haxx.se/">cURL</a>の<a href="http://curl.haxx.se/libcurl/">C APIマニュアル</a>を読んでいたら<a href="http://curl.haxx.se/libcurl/c/curl_multi_setopt.html">CURLMOPT_PIPELINING</a>というおもしろそうなオプションを見つけた。これはlibcurl 7.16.0 より加わった並列実行用Multiインターフェースのオプションで、設定することで<a href="http://en.wikipedia.org/wiki/HTTP_pipelining">HTTP Pipelining</a>なリクエストが送信できるようになる。HTTP Pipeliningとは個々のレスポンスを待つことなく複数のリクエストを投げることを意味する<a href="http://www.ietf.org/rfc/rfc2616.txt">HTTP/1.1</a>よりサポートされた通信パフォーマンス向上のためのテクニックである。</p>
<p>通常N個のリクエストを処理する際はN個ソケットがオープンされOPEN → REQUEST → RESPONSE → CLOSEなサイクルがN回行われる。Multiインターフェースによる並列処理の場合はOPEN → REQUEST → RESPONSE → CLOSEが並列に行われる。 またこれがkeep-aliveな接続であればOPEN → (REQUEST → RESPONSE) x N → CLOSEのようにクローズされるまで１ソケットが再利用される。 そしてHTTP Pipeliningはkeep-aliveな接続で使うテクニックであり、これが有効な場合は1ソケットオープン後にOPEN → (REQUEST x N) → (RESPONSE x N) → CLOSEのようにリクエストN個をレスポンスを待つことなく1ソケットに書き込むことができる。 まとめて送信される分パケット効率がアップし全体的なネットワークを流れるパケットの数を減らすことができ、 さらにまとめてリクエスト送信するので高レイテンシーなネットワークにおいては速度面で効果的といえる。 see also 「<a href="https://developer.mozilla.org/ja/HTTP_Pipelining_FAQ">Mozilla HTTP/1.1 パイプライン化 FAQ</a>」。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">(1) NOT keep-alive, single &nbsp; &nbsp; &nbsp; &nbsp; (OPEN → REQUEST → RESPONSE → CLOSE) x N<br />
(2) NOT keep-alive, multi &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(OPEN → REQUEST → RESPONSE → CLOSE) をN並列で行う<br />
(3) keep-alive &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; OPEN → (REQUEST → RESPONSE) x N → CLOSE<br />
(4) keep-alive, Pipelining &nbsp; &nbsp; &nbsp; &nbsp; OPEN → (REQUEST x N) → (RESPONSE x N) → CLOSE</div></div>
<p>というわけでいつものようにテストプログラムを作ってMultiインターフェースによる並列処理をHTTP Pipeliningありとなしで実行してみる。<br />
(環境 libcurl-7.19.5、httpd-2.2.2 on Debian-5.0.1 )</p>
<p><h2><strong>テストツールとそのコンパイル</strong></h2>
<p>cURL CAPIのMultiインターフェースを使って複数URLからfetchしてくるツールを作成した。</p>
<p><a href="http://github.com/yokawasa/any/blob/master/libcurl/multi_fetch.cpp">http://github.com/yokawasa/any/blob/master/libcurl/multi_fetch.cpp</a></p>
<p>標準的なcurl Multiインターフェースを使ったコードであるがポイントは次の部分。各リクエスト用のCURLハンドルでソケットの送信待ち時間を最小限にする<a href="http://curl.haxx.se/libcurl/c/curl_easy_setopt.html">CURLOPT_TCP_NODELAY</a>オプション（詳しくは「<a href="http://www.ibm.com/developerworks/jp/linux/library/l-hisock/index.html">Linuxにおけるソケット機能の向上</a>」を参照ください）と挙動把握のためにlibcurlのINFO情報を出力する<a href="http://curl.haxx.se/libcurl/c/curl_easy_setopt.html">CURLOPT_VERBOSE</a>オプションを有効にしている。またHTTP Pipeliningモード指定のときにMulti用ハンドルで<a href="http://curl.haxx.se/libcurl/c/curl_multi_setopt.html">CURLMOPT_PIPELINING</a>オプションを有効にしている。　以下該当箇所のコード断片。</p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">...<br />
<span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span>vector<span style="color: #339933;">&lt;</span>string<span style="color: #339933;">&gt;::</span><span style="color: #202020;">iterator</span> it<span style="color: #339933;">=</span>urls.<span style="color: #202020;">begin</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; it<span style="color: #339933;">!=</span>urls.<span style="color: #202020;">end</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #339933;">++</span>it<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; curl_easy_setopt<span style="color: #009900;">&#40;</span>c_handles<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> CURLOPT_URL<span style="color: #339933;">,</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>it<span style="color: #009900;">&#41;</span>.<span style="color: #202020;">c_str</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; curl_easy_setopt<span style="color: #009900;">&#40;</span>c_handles<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> CURLOPT_TCP_NODELAY<span style="color: #339933;">,</span> <span style="color: #0000dd;">1L</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; curl_easy_setopt<span style="color: #009900;">&#40;</span>c_handles<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> CURLOPT_VERBOSE<span style="color: #339933;">,</span> <span style="color: #0000dd;">1L</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; curl_multi_add_handle<span style="color: #009900;">&#40;</span>m_handle<span style="color: #339933;">,</span> c_handles<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; i<span style="color: #339933;">++;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>pipelining<span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; curl_multi_setopt<span style="color: #009900;">&#40;</span>m_handle<span style="color: #339933;">,</span> CURLMOPT_PIPELINING<span style="color: #339933;">,</span> <span style="color: #0000dd;">1L</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
...</div></div>
<p>上記URLのソースコードを取得して次のようにコンパイルを行う。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">g++ multi_fetch.cpp -o multi_fetch -I/usr/include -L/usr/lib -lcurl</div></div>
<p>使い方は次のように複数URLの書かれたファイルを指定する。-pオプションを加えてやることでHTTP Pipeliningモードでリクエスト送信を行う。 これはオプショナル。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Usage: ./multi_fetch &lt;options&gt;<br />
Options: -f file &nbsp;URL list file<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-p &nbsp; &nbsp; &nbsp; HTTP pipelining mode (optional)<br />
&nbsp;<br />
例) urls.txtに書かれた複数URLからHTTP Pipeliningモードでfetch<br />
$ ./multi_fetch -f urls.txt -p</div></div>
<p><h2><strong>NON HTTP Pipelining リクエスト送信</strong></h2>
<p>テスト用にホストfooとWebサーバ（apache）のあるホストbarを用意する。まずはHTTP Pipeliningオプションをはずした通常のmultiインターフェースによる並列実行を行う。リクエスト用CURLハンドルでCURLOPT_VERBOSEオプションが有効になっているので実行結果にlibcurlのINFO 情報も一緒に出力される。出力内容を全てここに貼り付けるには量が多すぎるので内容を簡略化してHTTP接続部分と各リクエストとそのレスポンスの最初の一行だけに絞る。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ cat urls.txt<br />
http://bar.yk55.com/test1.html<br />
http://bar.yk55.com/test2.html<br />
http://bar.yk55.com/test3.html<br />
http://bar.yk55.com/test4.html<br />
<br />
$ ./multi_fetch -f urls.txt &nbsp;2&gt;&amp;1 |tee /tmp/nonpipelined.out</div></div>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[出力結果]<br />
$ cat /tmp/nonpipelined.out<br />
<br />
* About to connect() to bar.yk55.com port 80 (#0) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
* About to connect() to bar.yk55.com port 80 (#1)<br />
* About to connect() to bar.yk55.com port 80 (#2)<br />
* About to connect() to bar.yk55.com port 80 (#3)<br />
* Connected to bar.yk55.com (192.168.1.5) port 80 (#0)<br />
* Connected to bar.yk55.com (192.168.1.5) port 80 (#1)<br />
* Connected to bar.yk55.com (192.168.1.5) port 80 (#2)<br />
* Connected to bar.yk55.com (192.168.1.5) port 80 (#3)<br />
&gt; GET /test1.html HTTP/1.1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&gt; GET /test2.html HTTP/1.1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&gt; GET /test3.html HTTP/1.1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&gt; GET /test4.html HTTP/1.1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&lt; HTTP/1.1 200 OK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
* Connection #1 to host bar.yk55.com left intact &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&lt; HTTP/1.1 200 OK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
* Connection #2 to host bar.yk55.com left intact &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&lt; HTTP/1.1 200 OK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
* Connection #3 to host bar.yk55.com left intact &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&lt; HTTP/1.1 200 OK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
* Connection #0 to host bar.yk55.com left intact</div></div>
<p>これを見ると並列にConnection #[0-3]の4つのソケットがオープンしてそれぞれにリクエスト、レスポンスが書き出され終了していることが分かる。 「(2)NOT keep-alive, multi」のパターンになっているといえる。想定どおり。</p>
<p><h2><strong>HTTP Pipeliningリクエスト送信</strong></h2>
<p>次に前テストと同様にホストfooからホストbar(Webサーバ)の4ファイル対してにHTTP Pipeliningなリクエストを送信してみる。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ cat urls.txt<br />
http://bar.yk55.com/test1.html<br />
http://bar.yk55.com/test2.html<br />
http://bar.yk55.com/test3.html<br />
http://bar.yk55.com/test4.html<br />
&nbsp;<br />
$ ./multi_fetch -f urls.txt -p　 2&gt;&amp;1 |tee /tmp/pipelined.out</div></div>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[出力結果]<br />
$ cat /tmp/pipelined.out<br />
<br />
* About to connect() to bar.yk55.com port 80 (#0)<br />
* Re-using existing connection! (#0) with host bar.yk55.com<br />
* Re-using existing connection! (#0) with host bar.yk55.com<br />
* Re-using existing connection! (#0) with host bar.yk55.com<br />
* Connected to bar.yk55.com (192.168.1.5) port 80 (#0) <br />
&gt; GET /test1.html HTTP/1.1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&lt; HTTP/1.1 200 OK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&gt; GET /test2.html HTTP/1.1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&gt; GET /test3.html HTTP/1.1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&gt; GET /test4.html HTTP/1.1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&lt; HTTP/1.1 200 OK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&lt; HTTP/1.1 200 OK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&lt; HTTP/1.1 200 OK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
* Connection #0 to host bar.yk55.com left intact</div></div>
<p>出力結果から、1つのソケットオープン(Connection #0)後に他のリクエスト達はConnectoin#0を 再利用しているのが分かる。 またtest1.htmlをGETするためのリクエスト送信後に「HTTP/1.1 200 OK&#8230;.」とレスポンスを受け、次にtest2.html～test4.html GETの3リクエストがレスポンスを待つことなく連続で送られ、その後それらのレスポンスを受けている。 「(4) keep-alive, Pipelining」のパターンになると予想していたのだが１つ目のリクエスト（REQUEST-a）だけがPipeliningではない。 試しにリクエスト数を増やしてみても同じ、１つ目のリクエストがPipeliningではなく、2番目以降のリクエストはPipeliningになっている。 今一理由がわからない。 ひょっとして実際の処理とは別にログ出力に問題があるのではないかと思い<a href="http://www.linux.or.jp/JM/html/tcpdump/man1/tcpdump.1.html">tcpdump</a>で実際のTCPパケットのやりとり確認してみる。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ sudo tcpdump -lX -s 1024 -i eth0 port 80 |tee /tmp/tcpdump.txt<br />
$ cat /tmp/tcpdump.txt<br />
<br />
*** SYN: Socketオープン<br />
01:27:14.155974 IP foo.43242 &gt; bar.http: S 3856091341:3856091341(0) win 5840 &lt;mss 1460,sackOK,timestamp 31004352 0,nop,wscale 6&gt;<br />
01:27:14.158135 IP bar.http &gt; foo.43242: S 2366776094:2366776094(0) ack 3856091342 win 5792 &lt;mss 1460,sackOK,timestamp 224898337 31004352,nop,wscale 2&gt;<br />
01:27:14.158197 IP foo.43242 &gt; bar.http: . ack 1 win 92 &lt;nop,nop,timestamp 31004352 224898337&gt;<br />
<br />
*** PUSH: 1stリクエスト<br />
01:27:14.156012 IP foo.43242 &gt; bar.http: P 1:63(62) ack 1 win 92 &lt;nop,nop,timestamp 31004352 224898337&gt;<br />
01:27:14.156080 IP bar.http &gt; foo.43242: . ack 63 win 1448 &lt;nop,nop,timestamp 224898337 31004352&gt;<br />
<br />
*** PUSH: 1stレスポンス<br />
01:27:14.158768 IP bar.http &gt; foo.43242: P 1:198(197) ack 63 win 1448 &lt;nop,nop,timestamp 224898340 31004352&gt;<br />
01:27:14.158930 IP foo.43242 &gt; bar.http: . ack 198 win 108 &lt;nop,nop,timestamp 31004353 224898340&gt;<br />
<br />
*** PUSH: 2nd, 3rd, 4thリクエスト<br />
01:27:14.159183 IP foo.43242 &gt; bar.http: P 63:125(62) ack 198 win 108 &lt;nop,nop,timestamp 31004353 224898340&gt;<br />
01:27:14.159277 IP foo.43242 &gt; bar.http: P 125:187(62) ack 198 win 108 &lt;nop,nop,timestamp 31004353 224898340&gt;<br />
01:27:14.159361 IP foo.43242 &gt; bar.http: P 187:249(62) ack 198 win 108 &lt;nop,nop,timestamp 31004353 224898340&gt;<br />
<br />
*** PUSH: &nbsp;2nd, 3rd, 4thまとめてレスポンス<br />
01:27:14.163514 IP bar.http &gt; foo.43242: P 198:789(591) ack 249 win 1448 &lt;nop,nop,timestamp 224898344 31004353&gt;<br />
<br />
*** FIN: &nbsp;Socket クローズ<br />
01:27:14.164128 IP foo.43242 &gt; bar.http: F 249:249(0) ack 789 win 127 &lt;nop,nop,timestamp 31004354 224898344&gt;<br />
01:27:14.164634 IP bar.http &gt; foo.43242: F 789:789(0) ack 250 win 1448 &lt;nop,nop,timestamp 224898345 31004354&gt;<br />
01:27:14.164780 IP foo.43242 &gt; bar.http: . ack 790 win 127 &lt;nop,nop,timestamp 31004354 224898345&gt;</div></div>
<p>tcpdumpの結果も変わらず同じ。 ログを見る限りオープン処理（SYNフラグの出力部分、いわゆる3way handshake）が行われた後、１つ目のリクエスト直後にレスポンスを受け、その後2番目以降のリクエストはレスポンスを待つことなくソケット書き込み、つまりPipeliningリクエスト送受信が行われている。　どうして１つ目だけがダメで、２つ目以降からうまくいくのだろう？？ (T . T)</p>
<p>細かくlibcurlのコードを追えばよいのだろうがこれ以上調査する気持ちにならないので取り敢えずここで終えておく。 続きはいつか。</p>
<p>おわり。</p>
<iframe src="http://www.facebook.com/plugins/like.php?href=http://yk55.com/blog/2010/04/20/curl_multi_http_pipelining_reques/&amp;layout=button_count&amp;show_faces=1&amp;width=450&amp;action=like&amp;colorscheme=light&amp;font=arial" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:25px"></iframe>]]></content:encoded>
			<wfw:commentRss>http://yk55.com/blog/2010/04/20/curl_multi_http_pipelining_reques/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	<!-- google_ad_section_end --></channel>
</rss>

