<?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; vs_httpd</title>
	<atom:link href="http://yk55.com/blog/tags/vs_httpd/feed/" rel="self" type="application/rss+xml" />
	<link>http://yk55.com/blog</link>
	<description>the place to organize and record my ideas ...</description>
	<lastBuildDate>Sun, 05 Feb 2012 15:16:55 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
	<!-- google_ad_section_end --><!-- google_ad_section_start(weight=ignore) -->	<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; fprintf<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; fprintf<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; fprintf<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> strrchr<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; fprintf<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; fprintf<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; fprintf<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; fprintf<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>
	<!-- google_ad_section_end --><!-- google_ad_section_start(weight=ignore) --></channel>
</rss>

