<?xml version="1.0" encoding="UTF-8" ?>
	<rss version = "2.0"  xmlns:blogChannel="http://backend.userland.com/blogChannelModule" >
		<channel>
			<title>Born Neet</title>
			<description>- The Emotional Programmer -</description>
			<link>http://blog.bornneet.com/</link>
			<language>ja</language>
			<copyright>Copyright (C) 2005-2008 SAMURAI-FACTORY ALL RIGHTS RESERVED.</copyright>

		<item>
			<title>Hello, httpd! C言語でWebServerを作ってみよう [第1回目]</title>
			<description>
			<![CDATA[<p>
さて、久々の勝手に連載企画を始めてみます。<br />
（ホントは先週に始まってる予定だったんですが…忙しすぎました）<br />
<br />
お題は最近興味津々のWebサーバの実装です。<br />
特にリリースとかは目指しませんが、<br />
この企画を通してApacheとかlightyのソースを読める力をつけたいと思ってます。<br />
<br />
それでは第1回目startです！<br />
今回は最初なので雛形となる超シンプルなサーバを作ります。<br />
今後、このソースを拡張していくことになります。<br />
<br />
ということで、完成品がこちら↓<br />
※ ようやく始めたGitHubに置いてます<br />
<br />
<a href="http://github.com/tnantoka/hello-httpd/blob/master/hello.c" class="external" target="_blank" title="新しいウィンドウで開きます">hello.c</a><br />
</p>
<pre class="source"><code>make
./hello 8080</code></pre>
<p>
で起動できます。<br />
<br />
今回実装したのは、「クライアント（同時接続1）に対してhtmlファイルを応答するだけのサーバ」です。<br />
特に難しいことはやってませんが、一応中身を説明しときます。
</p>
<h3>ソース解説</h3>
<pre class="source"><code>     1	#include &lt;stdio.h&gt;
     2	#include &lt;stdlib.h&gt;
     3	#include &lt;string.h&gt;
     4	#include &lt;netinet/in.h&gt;
     5	#include &lt;fcntl.h&gt;
     6	#include &lt;errno.h&gt;
     7	
     8	#define DOCUMENT_ROOT "./htdocs"
     9	#define BUF_SIZE 1024
    10	
    11	#define DEBUG</code></pre>
<p>冒頭ではヘッダファイルの読み込みと、<br />
ドキュメントルート、バッファサイズ、デバッグモードの指定をしています。<br />
</p>
<pre class="source"><code>    13	int main(int argc, char *argv[]) {
    14	
    15		struct sockaddr_in server;
    16		int sockfd;
    17		int port = (argc == 2) ? atoi(argv[1]) : 80;
    18	
    19		// socket作成
    20		if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
    21			perror("socket");
    22			exit(EXIT_FAILURE);
    23		}</code></pre>
<p>ここからmain関数に入ります。<br />
まず、変数の定義とポートの指定（※）をしています。<br />
※ コマンドライン引数がなければ80番を使用<br />
次にTCPのsocketを作成しています。<br />
</p>
<pre class="source"><code>    25		// Port, IPアドレスを設定(IPv4)
    26		memset(&server, 0, sizeof(server));
    27		server.sin_family = AF_INET;	
    28		server.sin_addr.s_addr = INADDR_ANY;
    29		server.sin_port = htons(port);
    30		
    31		// socketをすぐ再利用できるように
    32		char opt = 1;
    33		setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt));
    34	
    35		// ディスクリプタとPortを結び付ける
    36		if (bind(sockfd, (struct sockaddr *) &server, sizeof(server)) < 0) {
    37			perror("bind");
    38			exit(EXIT_FAILURE);
    39		}</code></pre>
<p>お次は、作成したsocketをportと結び付けます。（bind）<br />
<br />
一度clientから接続されると、プログラムを終了した後も一定時間bindできなくなるので、<br />
setsockoptですぐ再利用できるように指定しています。<br />
（が、効いてないようです。なんでだろ？macのせい…？）
</p>
<pre class="source"><code>    41		// listen準備
    42		if (listen(sockfd, SOMAXCONN) < 0) {
    43			perror("listen");
    44			exit(EXIT_FAILURE);
    45		}</code></pre>
<p>portをlisten可能な状態にします。<br />
listen()の第2引数は接続待ちできる数です。<br />
SOMAXCONNはデフォルト値で、環境毎に異なります。<br />
<br />
さて、これで準備は完了です。</p>
<pre class="source"><code>    47		// メインループ
    48		while (1) {
    49			struct sockaddr_in client;
    50			int newfd;
    51	
    52			char buf[BUF_SIZE] = "";
    53			char method[BUF_SIZE] = "";
    54			char url[BUF_SIZE] = "";
    55			char protocol[BUF_SIZE] = "";
    56			int len;
    57	
    58			int filefd;
    59			char file[BUF_SIZE] = "";</code></pre>
<p>いよいよメインループです。<br />
クライアントからの処理を無限ループで処理します。<br />
変数の説明は割愛します。</p>
<pre class="source"><code>    61			// clientからの接続を受け付ける
    62			memset(&client, 0, sizeof(client));
    63			len = sizeof(client);
    64			if ((newfd = accept(sockfd, (struct sockaddr *) &client, &len)) < 0) {
    65				perror("accept");
    66				exit(EXIT_FAILURE);
    67			}</code></pre>
<p>clientからの接続を受け付けます。<br />
以降の処理はacceptが返したディスクリプタnewfdに対して行います。</p>
<pre class="source"><code>    69			// request line読み込み
    70			if (recv(newfd, buf, sizeof(buf), 0) < 0) {
    71				perror("recv");
    72				exit(EXIT_FAILURE);
    73			}
    74			sscanf(buf, "%s %s %s", method, url, protocol);
    75	
    76			// request headerの終わりまで読み飛ばし
    77			// bodyは無視		
    78			do {
    79				if (strstr(buf, "\r\n\r\n")) {
    80					break;
    81				}
    82				if (strlen(buf) >= sizeof(buf)) {
    83					memset(&buf, 0, sizeof(buf));
    84				}
    85			} while (recv(newfd, buf+strlen(buf), sizeof(buf) - strlen(buf), 0) > 0);
</code></pre>
<p>clientからのリクエストを読み込みます。<br />
request lineは「GET / HTTP/1.0」になってるはずなので、ssanfします。<br />
<br />
すぐ応答を返してもおそらく処理してくれますが、<br />
一応ヘッダの終わり（\r\n\r\n）まで読み飛ばします。<br />
※ 1024バイトの倍数付近に\r\n\r\nが来るとダメです。<br />
　あと、bodyがあることは想定してません。</p>
<pre class="source"><code>    87			// ファイルパス生成（脆弱性有り）		
    88			sprintf(file, DOCUMENT_ROOT);
    89			strcat(file, url);		
    90
    91			// index.html補完
    92			if( file[strlen(file)-1] == '/' ) {
    93				strcat(file, "index.html" );
    94			}</code></pre>
<p>「ドキュメントルート+リクエストファイル名」でファイルパスを作成してます。<br />
末尾が「/」ならindex.htmlを追加します。</p>
<pre class="source"><code>    96			// debug
    97			#ifdef DEBUG
    98				sleep(1);
    99			#endif
</code></pre>
<p>デバッグ用に1秒sleepさせます。<br />
すぐ応答されると、同時接続数が増えても違いがわかりづらいので…</p>
<pre class="source"><code>   101			// （最低限の）header送信
   102			char *header = "HTTP/1.0 200 OK\n"
   103									"Content-type: text/html\n"
   104									"\n";
   105			send(newfd, header, strlen(header), 0);
   106	
   107			//	body送信
   108			if ((filefd = open(file, O_RDONLY)) < 0) {
   109				perror("open");
   110				fprintf(stderr, "file: %s\n", file);
   111			}
   112			else {
   113				while ((len = read(filefd, buf, sizeof(buf))) > 0) {
   114					if (send(newfd, buf, len, 0) < 0) {
   115						perror("send2");
   116					}
   117				}
   118			}
   119	
   120			close(newfd);</code></pre>
<p>最後にヘッダとファイルの中身を送信して、
ディスクリプタをcloseします。<br />
<br />
これで1クライアントの処理が終わり、<br />
ループ先頭に戻って次のクライアントを処理します。</p>
<h3>まとめ</h3>
<p>
超適当な説明でしたが、今回のソースはこんな感じです。<br />
<br />
C言語は大学でやった程度なので、<br />
たったこれだけのプログラムを作るのにもかなり苦労しました^^<br />
<br />
問題点だらけだと思うので、突っ込みいただけると幸いです。<br />
ここどういう意味？とかも大歓迎です。<br />
<br />
<strong style="color: red">あ、脆弱性だらけなので、くれぐれも公開サーバ上で起動しないで下さい。<br />
/etc/passwdとか見られちゃいますよ…</strong><br />
<br />
というところで、今回は終了です。<br />
今後は、</p>
<ul>
<li>マルチクライアント</li>
<li>CGI実行</li>
<li>html以外のファイル応答</li>
</ul>
<p>
あたりの機能を追加していきます。<br />
乞うご期待・・・！？
</p>]]>
			</description>
			<link>http://blog.bornneet.com/Entry/274/</link>
			<pubDate>Sun, 07 Mar 2010 03:46:39 GMT</pubDate>
		</item>
		<item>
			<title>C言語（NW）とWebサーバのお勉強「Portable minimal web servers」を読む</title>
			<description>
			<![CDATA[<p>
「Web Sockets云々の前にTCPのソケット通信わかってんの？」<br />
「う゛…」<br />
<br />
というやりとりが動機ってわけではないんですが、<br />
最近、Webサーバの実装に興味深々で、<br />
C言語でのネットワークプログラミングについて勉強を始めました。<br />
<br />
そんな中見つけたIBMの<a href="http://www.ibm.com/developerworks/jp/web/library/wa-ltwebserv/" class="external" target="_blank" title="新しいウィンドウで開きます">軽量 Web サーバー</a>という記事で、<br />
「Portable minimal web servers」なる論文が紹介されていました。<br />
<br />
非常に短くて素敵だったので、手始めにこいつをコードリーディングしてみることにしました。
</p>
<h3>予習</h3>
<p>
いきなりコードを見てもC初心者な僕にはさっぱりだと思ったので、<br />
以下の4冊から関連しそうな部分を流し読みして、わかった気になっておきました。<br />
これでもう怖くありません。<br />
（嘘です、まだまだ読み返さないとわからないことだらけです。）
</P>
<div class="hreview" ><a class="item url" href="http://www.amazon.co.jp/UNIX%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E5%85%A5%E9%96%80-%E9%9B%AA%E7%94%B0-%E4%BF%AE%E4%B8%80/dp/4774117544%3FSubscriptionId%3D15SMZCTB9V8NGR2TW082%26tag%3Dbornneet-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4774117544"><img src="http://ecx.images-amazon.com/images/I/41TQMN3JJML._SL160_.jpg" alt="photo" class="photo" style="float:left; margin: 0 15px 10px 10px; padding: 0;border:none;" /></a><dl style="margin-bottom:0.5em; text-align:left; min-height: 168px;font-size:12px;line-height:16px;"><dt class="fn"><a class="item url" href="http://www.amazon.co.jp/UNIX%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E5%85%A5%E9%96%80-%E9%9B%AA%E7%94%B0-%E4%BF%AE%E4%B8%80/dp/4774117544%3FSubscriptionId%3D15SMZCTB9V8NGR2TW082%26tag%3Dbornneet-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4774117544">UNIXネットワークプログラミング入門</a><img src='http://www.assoc-amazon.jp/e/ir?t=bornneet-22&l=ur2&o=9' width='1' height='1' border='0' alt='' /></dt><dd>技術評論社 2003-06-05</dd></dl><p class="gtools" style="font-size:10px;">by <a href="http://www.goodpic.com/mt/aws/index.html" >G-Tools</a> ,  <abbr class="dtreviewed" title="2010/02/21">2010/02/21</abbr></p></div>
<div class="hreview" ><a class="item url" href="http://www.amazon.co.jp/C%E8%A8%80%E8%AA%9E%E3%81%AB%E3%82%88%E3%82%8B%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-%E5%BF%9C%E7%94%A8%E7%B7%A8-%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E8%A8%88%E7%94%BB%E7%A0%94%E7%A9%B6%E6%89%80/dp/4274064875%3FSubscriptionId%3D15SMZCTB9V8NGR2TW082%26tag%3Dbornneet-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4274064875"><img src="http://ecx.images-amazon.com/images/I/41P9KWWFFJL._SL160_.jpg" alt="photo" class="photo" style="float:left; margin: 0 15px 10px 10px; padding: 0;border:none;" /></a><dl style="margin-bottom:0.5em; text-align:left; min-height: 168px;font-size:12px;line-height:16px;"><dt class="fn"><a class="item url" href="http://www.amazon.co.jp/C%E8%A8%80%E8%AA%9E%E3%81%AB%E3%82%88%E3%82%8B%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-%E5%BF%9C%E7%94%A8%E7%B7%A8-%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E8%A8%88%E7%94%BB%E7%A0%94%E7%A9%B6%E6%89%80/dp/4274064875%3FSubscriptionId%3D15SMZCTB9V8NGR2TW082%26tag%3Dbornneet-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4274064875">C言語によるプログラミング 応用編</a><img src='http://www.assoc-amazon.jp/e/ir?t=bornneet-22&l=ur2&o=9' width='1' height='1' border='0' alt='' /></dt><dd>システム計画研究所 </dd><dd>オーム社 2002-09</dd></dl><p class="gtools" style="font-size:10px;">by <a href="http://www.goodpic.com/mt/aws/index.html" >G-Tools</a> ,  <abbr class="dtreviewed" title="2010/02/21">2010/02/21</abbr></p></div>
<div class="hreview" ><a class="item url" href="http://www.amazon.co.jp/Unix-Linux%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E7%90%86%E8%AB%96%E3%81%A8%E5%AE%9F%E8%B7%B5-Bruce-Molay/dp/4048700219%3FSubscriptionId%3D15SMZCTB9V8NGR2TW082%26tag%3Dbornneet-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4048700219"><img src="http://ecx.images-amazon.com/images/I/51wNVx6X2RL._SL160_.jpg" alt="photo" class="photo" style="float:left; margin: 0 15px 10px 10px; padding: 0;border:none;" /></a><dl style="margin-bottom:0.5em; text-align:left; min-height: 168px;font-size:12px;line-height:16px;"><dt class="fn"><a class="item url" href="http://www.amazon.co.jp/Unix-Linux%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E7%90%86%E8%AB%96%E3%81%A8%E5%AE%9F%E8%B7%B5-Bruce-Molay/dp/4048700219%3FSubscriptionId%3D15SMZCTB9V8NGR2TW082%26tag%3Dbornneet-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4048700219">Unix/Linuxプログラミング理論と実践</a><img src='http://www.assoc-amazon.jp/e/ir?t=bornneet-22&l=ur2&o=9' width='1' height='1' border='0' alt='' /></dt><dd>長尾 高弘 </dd><dd>アスキー・メディアワークス 2008-04-21</dd></dl><p class="gtools" style="font-size:10px;">by <a href="http://www.goodpic.com/mt/aws/index.html" >G-Tools</a> ,  <abbr class="dtreviewed" title="2010/02/21">2010/02/21</abbr></p></div>
<div class="hreview" ><a class="item url" href="http://www.amazon.co.jp/C%E8%A8%80%E8%AA%9E%E3%81%AB%E3%82%88%E3%82%8BTCP-IP%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-%E5%B0%8F%E4%BF%A3-%E5%85%89%E4%B9%8B/dp/4894715163%3FSubscriptionId%3D15SMZCTB9V8NGR2TW082%26tag%3Dbornneet-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4894715163"><img src="http://ecx.images-amazon.com/images/I/51HYHF18M8L._SL160_.jpg" alt="photo" class="photo" style="float:left; margin: 0 15px 10px 10px; padding: 0;border:none;" /></a><dl style="margin-bottom:0.5em; text-align:left; min-height: 168px;font-size:12px;line-height:16px;"><dt class="fn"><a class="item url" href="http://www.amazon.co.jp/C%E8%A8%80%E8%AA%9E%E3%81%AB%E3%82%88%E3%82%8BTCP-IP%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-%E5%B0%8F%E4%BF%A3-%E5%85%89%E4%B9%8B/dp/4894715163%3FSubscriptionId%3D15SMZCTB9V8NGR2TW082%26tag%3Dbornneet-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4894715163">C言語によるTCP/IPネットワークプログラミング</a><img src='http://www.assoc-amazon.jp/e/ir?t=bornneet-22&l=ur2&o=9' width='1' height='1' border='0' alt='' /></dt><dd>ピアソンエデュケーション 2001-09</dd></dl><p class="gtools" style="font-size:10px;">by <a href="http://www.goodpic.com/mt/aws/index.html" >G-Tools</a> ,  <abbr class="dtreviewed" title="2010/02/21">2010/02/21</abbr></p></div>
<h3>論文の内容</h3>
<p>
翻訳しようかと思いましたが、あんまりコードの説明もなさそうだったのでやめときました。<br />
<br />
たぶん、
</p>
<blockquote><p>Apacheとか複雑なのもいいけど、シンプルさも大事でしょ？<br />
ちょっとCとbashで作ってみたから、紹介するよ！<br />
GPLだからご自由にどうぞ。</p></blockquote>
<p>
みたいなことが書いてあるはずです。
</p>
<h3>動作確認</h3>
<p>
ソースを読む前に、まずは動くか確認。<br />
…以下の手順で問題なく動きました。
</p>
<pre class="source"><code>準備
cd /Users/t/c/szerver
mkdir htdocs

echo test > htdocs/index.html

設定変更
vi szerver.c
#define PORT 8080
#define DOCUMENTROOT "/Users/t/c/szerver/htdocs"

コンパイル
gcc szerver.c -o szerver

実行
./szerver.c
NW通信の警告popupが出たら「許可」

ブラウザから
http://localhost:8080/
testと表示されればOK</code></pre>
<h3>コードリーディング</h3>
<p>
<a href="ftp://linux.pte.hu/pub/minwebservers/szerver.c">元のソースはこちら</a>（FTPです）<br />
<br />
一部ハンガリー語があったので、<br />
英訳→日訳しつつ読んでいきました。<br />
<br />
最終的には下記のようにコメントをつけまくって理解したつもりになってます。<br />
間違ってる部分があればご指摘いただけると幸いです。<br />
<br />
いやぁやっぱ公開するコードの変数名とかは英語で書かないと駄目ですね。<br />
非日本語圏の人が「gokei_keisan」とかに出くわしたら、やっぱテンパるんだろうなぁ…。
</p>
<pre class="source"><code>/* 
  ヘッダファイルのinclude
  TODO: 各ヘッダを何のために使ってるか
*/
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;syslog.h&gt;	//syslog出力
#include &lt;unistd.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/socket.h&gt;
#include &lt;netinet/in.h&gt;
#include &lt;netdb.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;unistd.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;sys/wait.h&gt;
#include &lt;fnmatch.h&gt;
#include &lt;libgen.h&gt;

// デバッグログを表示したい時はdefineする
/*#define DEBUG*/

// listenポートとドキュメントルート
#define PORT 8080
#define DOCUMENTROOT "/Users/t/c/szerver/htdocs"

char		request_file[1024];	//
void		*memory_buffer;	// 応答するファイルの内容を読み込むバッファ
size_t	buffer_size;	// 読み込むファイルのサイズ（バッファのサイズ）
int			sock;	//

/*
  エラーをsyslogに吐く。
  hibaはerrorの意味
*/
void hiba( const char *hiba ){
	syslog( 0, hiba );
	exit(1);
}/*hiba*/

/*
  応答するファイルをmemory_bufferに読み込む
*/
int loadfile( ){
	struct stat	size;	// ファイル情報
	int infile;	// ディスクリプタ

	// ファイルの情報を取得
	if( stat( request_file, &size ) != 0 )
		hiba( "File not found.¥n" );

	// サイズを取得
	buffer_size = size.st_size;
	
	// サイズ文のバッファを確保
	memory_buffer=malloc( buffer_size );
	if( memory_buffer==NULL )
		hiba( "Out of memory.¥n" );

	// ファイルを開いて読み込む
	infile=open( request_file, O_RDONLY );
	if( read( infile, memory_buffer, buffer_size ) != buffer_size )
		hiba( "Unable to read file." );

	// ファイルを閉じる
	close( infile );
}/*sendfile*/	/* loadfileのタイポ */

/*
　	socketのbindまでを行う
　	kapuはport
　	nyitはopen
　	-asaは謎
*/
int kapu_nyitasa( void ){
	int kapu;
	struct sockaddr_in  barki; // サーバが接続待ちするIP、ポート情報（barki=any）

	// socketの作成
	// PF_INET(IPV4)
	// SOCK_STREAM(ストリーム)
	// 0（IPPROTO_TCPが指定される）
	kapu = socket (PF_INET, SOCK_STREAM, 0);
	if(kapu < 0)
		hiba( "Error open socket.¥n" );

	barki.sin_family=AF_INET; // アドレスファミリ（インターネット）
	barki.sin_port=htons(PORT);	// portをNWバイトオーダーで指定
	barki.sin_addr.s_addr=htonl(INADDR_ANY);	// ホスト上の全IP

	// ディスクリプタ（kapu）とポートのム結び付け
	if(bind(kapu, (struct sockaddr *) &barki, sizeof(barki)) < 0)
		hiba( "Error binding socket.¥n" );
	
	return kapu;
}/*kapu_nyitasa*/


/*
	olvasas = read
*/
int olvasas( int kapu ){
	char memoria[1024];  // リクエスト読み込みバッファ（memoria = memory）
	int n;
	
	// request_fileにDOCUMENTROOTを書き込む
	sprintf( request_file, DOCUMENTROOT );

	// memoriaにrequestを読み込む
	n=read(kapu, memoria, 1024);
	if( n < 0 )
		hiba( "Error reading socket.¥n" );

	// リクエストラインからファイル名を取得して、DOCUMENTROOT以降に追記
	sscanf(memoria, "GET %s", 
			&request_file[strlen(DOCUMENTROOT)] );
	
	// スラッシュで終わってたらindex.htmlを付ける
	if( request_file[strlen(request_file)-1]=='/' )
			sprintf(&request_file[strlen(request_file)], "index.html" );
	
	// デバッグログ
	#ifdef DEBUG
	syslog( 0, "File request: %s¥n", request_file );
	#endif

	return( n );
}/*olvasas*/
	
/*
 iras = writeっぽい
*/
int iras( int kapu ){
	// レスポンスのテンプレ
	char head_template[]="HTTP/1.0 200 OK¥r¥n¥
Server: miniserver/0.1¥r¥n¥
Connection: close¥r¥n¥
Content-Type: %s¥r¥n¥r¥n";

char	head[512];	// レスポンスするヘッダ
char  *type;
int		irt;

	// Content-Typeの設定
	type="text/html";
	if( fnmatch("*.gif", basename(request_file), 0) == 0 )
		type="image/gif";
	if( fnmatch("*.jpg", basename(request_file), 0) == 0 )
		type="image/jpeg";
	if( fnmatch("*.png", basename(request_file), 0) == 0 )
		type="image/png";
	
	// ヘッダを作成
	sprintf( head, head_template, type ); 

	// ヘッダの送信
	irt=write( kapu, head, strlen(head));
	
	// データの送信
	if( memory_buffer != NULL )
		irt=write( kapu, memory_buffer, buffer_size );
	else
		syslog( 0, "Error: no data to send.¥n" );
 
	return(1);
}/*iras*/

/*
  メインループ
*/
int  mainloop( void ){
	int new;	// 接続完了後のディスクリプタ
	int i;
	struct sockaddr_in clientname;	// 接続したクライアントの情報
	size_t size;

	// socketの作成
	sock=kapu_nyitasa();
	
	while( 1 ){
		// socketをlisten可能状態に
		if( listen (sock, 1) < 0 )
			hiba( "Error while listening." );

			// クライアントと接続
			size = sizeof (clientname);
			new = accept(sock, (struct sockaddr *) &clientname, &size);

			/*waitpid( WAIT_ANY, NULL, WNOHANG );*/
			// 子プロセスでリクエストを処理
			if( fork() != 0 ){
				olvasas( new );	// リクエストからファイル名取得
				loadfile(); // ファイルの読み込み
				iras( new ); // ヘッダ・データの送信
				shutdown( new, 2 ); // TODO: closeとの差とか
				if( memory_buffer != NULL )
					free(memory_buffer);
				return(0);
			}
	}/*while*/
}/*mainloop*/
 
/*
  終了系のシグナルを受けた時の処理
*/
void signal_handler( int signal ){
	shutdown( sock, 2 );
	hiba("Exiting...¥n");
}/*signal_handler*/	


/*
  main関数
*/
int main( int argc, char *argv[] ){
	// syslog準備＆スタートメッセージ
	openlog( "webserver", LOG_PID, LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG) );
	syslog( 0, "Miniserver started." );
	
	// 終了系シグナルの処理
	signal( SIGINT, signal_handler );
	signal( SIGKILL, signal_handler );
	signal( SIGTERM, signal_handler );
	
	daemon( 0, 0 );	// daemon化（TODO: 初めて見た）
	mainloop();	// mainloop実行
	return(0);
}/*main*/</code></pre>
<p>
うーん、やっぱ自分でコード書いてみないとダメだなー。<br />
頑張るかー。
</p>
]]>
			</description>
			<link>http://blog.bornneet.com/Entry/273/</link>
			<pubDate>Sun, 21 Feb 2010 14:47:07 GMT</pubDate>
		</item>
		<item>
			<title>mod_websocket for lighttpdをMacで動かしてみる3（ssl,wss）</title>
			<description>
			<![CDATA[<p>
うちのOS X10.6でも無事動いたmod_websocketですが、<br />
証明書の設定が面倒でwss(SSL)を試してみませんでした。<br />
<br />
実際始めてしまえばそんなに面倒じゃないんですが、<br />
やるまでがね…。<br />
<br />
ってわけで、手順を残しておきますので、ご自由にどうぞ。<br />
<br />
なお、参考にしたのは以下のサイトです。<br />
<a href="http://www.atmarkit.co.jp/flinux/rensai/linuxtips/846lighttpdssl.html" class="external" target="_blank" title="新しいウィンドウで開きます">Webサーバ「lighttpd」でSSLを使うには − ＠IT</a><br />
<a href="http://ggutter.blogspot.com/2009/07/lighttpd-ssl.html" class="external" target="_blank" title="新しいウィンドウで開きます">今日も明日もググったー: lighttpd ssl</a><br />
<a href="http://d.hatena.ne.jp/japanrock_pg/20070920/1190260452" class="external" target="_blank" title="新しいウィンドウで開きます">Rails + lighttpd + SSL - プログラマ 福重 伸太朗 〜基本へ帰ろう〜</a>
</p>
<pre class="source"><code><h4>作業ディレクトリへ</h4>
cd lighty/lighttpd-1.4.26


<h4>lighttpdをSSL ONでコンパイルし直し</h4>
./configure --prefix=/Users/t/lighty/ --with-openssl
(network-opensslがenableの方に表示されればOK)
make
make install
cd ..


<h4>lighttpdの設定</h4>
vi etc/lighttpd/lighttpd.conf
 $SERVER["socket"] == ":8443" {
       ssl.engine                  = "enable"
       ssl.pemfile                 = "/Users/t/lighty/etc/lighttpd/ssl/server.pem"
}
:wq
※ ここではサボってますが、広く公開する場合等（っていうか原則）は、
　ドキュメントルートを分けましょう。

<h4>オレオレ証明書の作成</h4>
mkdir etc/lighttpd/ssl/
openssl req -new -x509 -keyout server.pem -out server.pem 
Generating a 1024 bit RSA private key
.........++++++
.............................++++++
writing new private key to 'server.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
Verify failure
Enter PEM pass phrase:****
Verifying - Enter PEM pass phrase:****
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Tokyo
Locality Name (eg, city) []:Koto
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Born Neet
Organizational Unit Name (eg, section) []:    
Common Name (eg, YOUR name) []:localhost
Email Address []:

ls
server.pem
cd ~/lighty


<h4>起動</h4>
lighttpd -f etc/lighttpd/lighttpd.conf
Enter PEM pass phrase: ****


<h4>HTTPSのテスト（ブラウザから）</h4>
https://localhost:8443/
test
（証明書の警告は無視）


<h4>チャットサンプル(wss版）の準備</h4>
cp -p srv/www/htdocs/ws_chat.html srv/www/htdocs/wss_chat.html 
vi srv/www/htdocs/wss_chat.html 
var ws = new WebSocket("wss://127.0.0.1:8443/chat");
:wq


<h4>chatサーバの起動</h4>
mod_websocket/src/sample/ws_chat 9001
ポップアップが出るので許可する


<h4>Chatのテスト（Chromeから）</h4>
<del>http://localhost:8080/wss_chat.html</del>
https://localhost:8443/wss_chat.html
（wss通信だけじゃなくwss_chat.html取得の通信も暗号化すべき）
<strong style="color: red">動いた！！</strong></code></pre>
<p>
ん…wssってこれでいいんだっけ？<br />
<br />
何か間違ってる気がするので突っ込みに期待…<br />
…じゃなく後で勉強しとこう。<br />
<br />
nori2048さんに早速突っ込みをいただきました。（2010/2/20 00:10）<br />
コメント欄も合わせてご覧下さい。<br />
（記事にも追記しています。）
</p>
]]>
			</description>
			<link>http://blog.bornneet.com/Entry/272/</link>
			<pubDate>Fri, 19 Feb 2010 13:44:40 GMT</pubDate>
		</item>
		<item>
			<title>mod_websocket for lighttpdをMacで動かしてみる2（無事成功！）</title>
			<description>
			<![CDATA[<p>
先日失敗したmod_websocket on snow leopardですが、<br />
作者のnori0428さんが早くも修正版をリリースしてくださいました。<br />
<br />
動かないと文句を付けた手前、早く試してみないと…と思ってたんですが、<br />
今週は忙しくて週末になってしまいました。
<br />
というわけで、リベンジです。<br />
（僕は何もしてませんが）<br />
<br />
結果は…<br />
…無事、動きました！！<br />
<br />
Mac OS 10.6の人は以下の手順で使えると思いますよー。<br />
（wssはスルーしてますが）
</p>
<pre class="source"><code><h4>作業ディレクトリ</h4>
mdkir lighty
cd lighty

<h4><a href="http://github.com/nori0428/mod_websocket" class="external" target="_blank" title="新しいウィンドウで開きます">mod_websocket</a>のダウンロード</h4>
git clone git://github.com/nori0428/mod_websocket.git

<h4><a href="http://www.lighttpd.net/" class="external" target="_blank" title="新しいウィンドウで開きます">lighttpd</a>のダウンロード</h4>
curl -O http://download.lighttpd.net/lighttpd/releases-1.4.x/lighttpd-1.4.26.tar.gz

<h4>とりあえず、makeに必須のライブラリをインストール</h4>
sudo port install autoconf
sudo port install Automake
sudo port install pcre
zlibとbzip2はデフォルトで入ってるっぽい。

<h4>そしてmod_websocketへ</h4>
tar xf lighttpd-1.4.26.tar.gz
cd lighttpd-1.4.26

<h4>パッチ当て</h4>
patch -p1 < ../mod_websocket/src/mod_websocket.patch

cp ../mod_websocket/src/mod_websocket.c src/


<h4>ホームディレクトリ内にインストール</h4>
./autogen.sh
./configure --prefix=/Users/t/lighty/
make
make install

<h4>確認（ファイルがあればOK）</h4>
ls -l ../lib/mod_websocket.*
-rwxr-xr-x  1 t  staff   1022  2 19 01:58 ../lib/mod_websocket.la
-rwxr-xr-x  1 t  staff  26016  2 19 01:58 ../lib/mod_websocket.so

<h4>パス追加</h4>
vi ~/.profile
export PATH=/Users/t/lighty/sbin:$PATH
:wq
source ~/.profile

<h4>lighttpdの設定</h4>
mkdir -p ../etc/lighttpd
cp -p doc/lighttpd.conf ../etc/lighttpd/
cd ..
vi etc/lighttpd/lighttpd.conf
server.modules              = ( "mod_websocket", 
server.port                = 8080
server.document-root        = "/Users/t/lighty/srv/www/htdocs/"
server.errorlog             = "/Users/t/lighty/var/log/lighttpd/error.log"
accesslog.filename          = "/Users/t/lighty/var/log/lighttpd/access.log"
websocket.server = (
      "/echo" => ( "host" => "127.0.0.1", "port" => 9000 ),
      "/chat" => ( "host" => "127.0.0.1", "port" => 9001 )
)
:wq

<h4>ディスクトリとテストコンテンツの作成</h4>
mkdir -p srv/www/htdocs
mkdir -p var/log/lighttpd
mkdir -p var/run/lighttpd
echo test > srv/www/htdocs/index.html

<h4>起動（confファイルを指定しないと何かエラーになる）</h4>
lighttpd -t -f etc/lighttpd/lighttpd.conf
Syntax OK
lighttpd -f etc/lighttpd/lighttpd.conf

<h4>Webサーバのテスト（ブラウザから）</h4>
http://localhost:8080/
test

<h4>チャットサンプルの準備</h4>
cp mod_websocket/html/ws_chat.html srv/www/htdocs/
vi srv/www/htdocs/ws_chat.html 
var ws = new WebSocket("ws://127.0.0.1:8080/chat");
:wq

<h4>libevent（ソースからインストールし直さないとダメっぽい）</h4>
sudo port uninstall libevent
curl -O http://www.monkey.org/~provos/libevent-1.4.13-stable.tar.gz
tar xf libevent-1.4.13-stable.tar.gz 
cd libevent-1.4.13-stable
make
sudo make install

<h4>サンプルのmake</h4>
cd ..
cd mod_websocket/src/sample
make

<h4>chatサーバの起動</h4>
cd ~/lighty
mod_websocket/src/sample/ws_chat 9001
ポップアップが出るので 「許可」

<h4>Chatのテスト（Chromeから）</h4>
http://localhost:8080/ws_chat.html
<strong style="color: red">動いた！！</strong></code></pre>
<p>
wss(ssl)を有効化するのと、自分でサンプル作ってみるのが宿題。<br />
あと、ソースも読んでみないと。<br />
<br />
よーし、弄り倒すぞー。
</p>
]]>
			</description>
			<link>http://blog.bornneet.com/Entry/271/</link>
			<pubDate>Fri, 19 Feb 2010 12:23:12 GMT</pubDate>
		</item>
		<item>
			<title>mod_websocket for lighttpdをMacで動かそうとしたけど、失敗した</title>
			<description>
			<![CDATA[<p>今日昼間、ふとメールチェックしていると、<br />
html5-developers-jpに素敵な投稿がありました。<br />
<br />
「lighttpdでwebsocketできるモジュール作ったよ！」<br />
<br />
これは試してみるしかないでしょう、と今日はこのことしか考えてませんでした。<br />
が、残業やらなんやらで気づけばこの時間です。<br />
まぁ仕事なんで仕方ない。<br />
<br />
愚痴はこのぐらいにして、早速やってみます。<br />
<br />
基本的には<a href="http://github.com/nori0428/mod_websocket/blob/master/INSTALL" class="external" target="_blank" title="新しいウィンドウで開きます">INSTALL at master from nori0428's mod_websocket - GitHub</a>の通りのことをやっただけです。<br />
なんかうまく行きませんでしたが、誰かの役に立つかもしれないので、一応ログを残しておきます。
</p>
<h3>インストール</h3>
<h4></h4>
<pre class="source"><code>準備
mdkir lighty
cd lighty

<a href="http://github.com/nori0428/mod_websocket" class="external" target="_blank" title="新しいウィンドウで開きます">mod_websocket</a>のダウンロード
<strong>git clone git://github.com/nori0428/mod_websocket.git</strong>

<a href="http://www.lighttpd.net/" class="external" target="_blank" title="新しいウィンドウで開きます">lighttpd</a>のダウンロード
<strong>curl -O http://download.lighttpd.net/lighttpd/releases-1.4.x/lighttpd-1.4.26.tar.gz</strong>
<strong>tar xf lighttpd-1.4.26.tar.gz</strong>

<strong>cd lighttpd-1.4.26</strong>

パッチ当て（実は初！）
<strong>patch -p1 < ../mod_websocket/src/mod_websocket.patch</strong>

<strong>cp ../mod_websocket/src/mod_websocket.c src/</strong>

<strong>./autogen.sh</strong>
configure.ac:1: error: possibly undefined macro: dnl
      If this token and others are legitimate, please use m4_pattern_allow.
      See the Autoconf documentation.
configure.ac:71: error: possibly undefined macro: AC_DEFINE
→エラー…

sudo port install autoconf

aclocal.m4:14: error: this file was generated for autoconf 2.61.
You have another version of autoconf.  If you want to use that,
you should regenerate the build system entirely.
→まだエラー

sudo port install Automake
→行けた

<strong>./configure --prefix=/Users/t/lighty/</strong>
checking for pcre-config... no
configure: error: pcre-config not found, install the pcre-devel package or build with --without-pcre
→またエラー

sudo port install pcre
→ようやく行けた

<strong>make</strong>
Undefined symbols:
  "_network_write_chunkqueue", referenced from:
      _websocket_write_request in mod_websocket.o
→もうやになってきた…

sudo port install gcc45
※ gccいっぱいありすぎ→<a href="http://d.hatena.ne.jp/hnw/20080819" class="external" target="_blank" title="新しいウィンドウで開きます">MacPortsからインストールしたgccについて混乱中 - hnwの日記</a>
※ <a href="http://d.hatena.ne.jp/mojin/20090516/1242463801" class="external" target="_blank" title="新しいウィンドウで開きます">4時間かかるらしいので中断</a>

んーわからん。
lighty単体をインストールしてみる
cd ..
rm -rf lighttpd-1.4.26
tar -xf lighttpd-1.4.26.tar.gz
cd lighttpd-1.4.26
./configure --prefix=/Users/t/lighty/
make
make install
→普通にできた。

もっかい1から
cd lighttpd-1.4.26
　：
　：
駄目だこりゃ。　

</code></pre>
<p>
うーん、今日のところは寝るとしよう。<br />
（gccのせいかもしれないので、アップデートだけ流しておこう）<br />
→gccのアップデートは意味なかったです。[2010/2/17 8:00]<br />
<br />
もっとじっくり触りたいのに、時間が足りないなー。<br />
とりあえず、今週末の遊び道具はこいつで決まりかな。<br />
（Cの勉強も兼ねてソースも読もうっと）
</p>
]]>
			</description>
			<link>http://blog.bornneet.com/Entry/270/</link>
			<pubDate>Tue, 16 Feb 2010 16:04:10 GMT</pubDate>
		</item>
		<item>
			<title>pdicoならたった105円でiPhone/iPod touchで英辞郎が使える</title>
			<description>
			<![CDATA[<p>
なんと2月初投稿…。<br />
最近はわりとコンスタントにポストできてたのになぁ。<br />
<br />
今日はiPhoneの話題です。<br />
<br />
iPhoneで辞書を使いたい、で、やっぱ英辞郎のデータがいいよね、<br />
ってこと探して2つぐらいアプリを見つけたんだけど、どっちも1000円して手を出しづらい。<br />
<br />
どうしようかなぁと思ってたら、PDIC形式の辞書データを使える<a href="http://d.hatena.ne.jp/kkatsuyoshi/20091214/1260805347" class="external" target="_blank" title="新しいウィンドウで開きます">pdico</a>なるアプリを発見。<br />
既にPC版の英辞郎を持ってる僕としては「これは！」って感じだったので、<br />
早速使ってみました。<br />
<br />
辞書データの使い回しがどこまで許されるのかよくわからんけど、<br />
PCの方をアンインストールしちゃえばなんの問題もないでしょう。<br />
※ どうせ最近macしか使ってないからPC版の英辞郎起動すらしてないし。<br />
<br />
というわけで以下手順。
</p>
<h3>辞書ファイルの準備</h3>
<p>
まずは、英辞郎をインストール。<br />
CDを入れて自動再生に任せるだけですね。<br />
ちなみに使ったのは大学時代に買った第3版です。<br />
<br />
Personal Dictionary for EIJIRO IIIを起動。<br />
Tool→辞書の変換。<br />
C:\Program Files\PDIC_for_EIJIRO_III内のDICファイルを全て選択。<br />
デスクトップにeijiro.dicとかの名前で保存。<br />
（途中なんかダイアログが出てくるけどよくわからんので「以降自動処理」で。）<br />
<br />
※ pdicoは複数の辞書ファイルを同時に使えるので、上記手順は必須じゃないです。<br />
　また、その場合インストールしなくても、D:\EIJIROとかのデータが使えます。<br />
<br />
<h3>pdicoへの転送</h3>
<p>
まず、PCとiPhoneを同じ無線LANにつなぎましょう。<br />
<br />
pdicoを起動して設定を開きます。<br />
<br />
辞書を追加から、
ファイル名は上で作った「eijiro.dic」を指定して次へ。<br />
<br />
ブラウザからiPhoneのIPアドレス:8080にアクセス。<br />
（アクセス先はpdico上に表示されています。）<br />
<br />
辞書ファイルを選んで送信。<br />
※ Windows Defenderが邪魔してきたら止めちゃいましょう。<br />
※ 途中で電源に接続すると失敗するかもしれません。<br />
</p>
<h3>まとめ</h3>
<p>
はい、これだけでiPhone上で英辞郎をインクリメンタル検索できる環境が整っちゃいます。<br />
素晴らしいアプリですね！<br />
検索もかなりサクサク動いてストレスはありません。<br />
<br />
あとは検索履歴と部分一致（今は前方一致）、大/小文字無視とかが<br />
できれば言う事なしですね。<br />
<br />
PCの英辞郎を既に持ってる人は是非使ってみて下さい。
</p>]]>
			</description>
			<link>http://blog.bornneet.com/Entry/269/</link>
			<pubDate>Thu, 11 Feb 2010 13:58:53 GMT</pubDate>
		</item>
		<item>
			<title>node.websocket.jsで超適当ホワイトボードアプリ</title>
			<description>
			<![CDATA[<p>
今週は仕事と<a href="http://www.amazon.co.jp/gp/product/B000UTH1XK?ie=UTF8&tag=tnantoka-22&linkCode=as2&camp=247&creative=7399&creativeASIN=B000UTH1XK" target="_blank">ドラクエVI</a><img src="http://www.assoc-amazon.jp/e/ir?t=tnantoka-22&l=as2&o=9&a=B000UTH1XK" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />が忙しくて全然勉強の時間がとれませんでした。<br />
（モンスターが仲間に入らないのと難易度が下がってるのにはがっかりしましたが、やっぱり6はいいですね。）<br />
というわけで週末、しかも2日目に慌ててやってみます。<br />
<br />
触るのは、引き続きWeb Socket(s)。<br />
前回のでAPI（クライアントサイド。つまりJS。sがつく方）は何となくイメージできたかなぁという感じ。<br />
しかし、プロトコル（Web Socket protocol。こっちはsがつかない）はイマイチ理解できてません。<br />
<br />
こういう時はやっぱり手を動かすのが一番ということでとりあえず何か作ってみます。<br />
※ ほんとはパケットキャプチャ取りたかったんですがうまくいかなかったので断念<br />
<br />
それでは始めましょう。<br />
<br />
まずは参考記事探しから。<br />
<br />
<a href="http://d.hatena.ne.jp/ymotongpoo/20091005/1254750201" class="external" target="_blank" title="新しいウィンドウで開きます">Web Socket ProtocolのRFC和訳 - YAMAGUCHI::weblog</a><br />
ないと思ってたプロトコルの日本語訳がありました。感謝です。<br />
ただこの仕様短いのはいいんだけど、細かい説明が全然ない・・・。<br />
websoket-protcol:ヘッダって何の意味があるんだー。<br />
（node.websokcet.jsではまだ未実装って書いてあるし）<br />
<br />
<a href="http://www.infoq.com/jp/news/2008/12/websockets-vs-comet-ajax" class="external" target="_blank" title="新しいウィンドウで開きます">InfoQ: HTML 5 Web Sockets vs. Comet and Ajax</a><br />
仕様のこととかは詳しく書いてませんがおもしろかったです。<br />
<br />
<a href="http://ido.nu/kuma/2009/08/25/pubsubhubbub-web-sockets-client-side-javascript/" class="external" target="_blank" title="新しいウィンドウで開きます">PubSubHubbubとWebSocketsとクライアントサイドのjavascript « ku</a><br />
こちらも他の実現方法との比較。読みやすいです。<br />
<br />
<a href="http://www.slideshare.net/tottyjp/html5-web-applications" class="external" target="_blank" title="新しいウィンドウで開きます">Html5 Web Applications</a><br />
<a href="http://www.slideshare.net/tottyjp/html5-web-applications-2" class="external" target="_blank" title="新しいウィンドウで開きます">Html5, Web Applications 2</a><br />
HTML5のWebアプリ関連仕様をサクっとまとめた素晴らしいプレゼンです。<br />
<br />
[追記（2010/1/31 14:15）]<br />
おっと、忘れてた。<br />
<a href="http://www.studyinghttp.net/rfc_ja/rfc2817" class="external" target="_blank" title="新しいウィンドウで開きます">HTTP/1.1 から TLS へのアップグレード</a><br />
<a href="http://suika.fam.cx/~wakaba/wiki/sw/n/Upgrade" class="external" target="_blank" title="新しいウィンドウで開きます">Upgrade</a><br />
HTTPのUpgradeについて。さっぱりわからん。<br />
[/追記]<br />
<br />
やっぱまだ日本語のソースは少ないですねぇ。<br />
<br />
ネットサーフィンはこれぐらいにして、<br />
うーん・・・Cometアプリの代表例ホワイトボードでも作ってみますか。<br />
<br />
というわけで、できたのがこちら。<br />
<br />
ソースはいつも通りご自由に。<br />
説明はコメントで。そんな難しいことはやってません。<br />
（セキュリティ0なので間違っても公開しないで下さいね）<br />
<br />
<img src="http://file.blog.bornneet.com/wb.png" /><br />
<br />
うーん、一応思った通りに動いたけど、サーバ側でsetIntervalやるのは綺麗じゃないなー。<br />
このコード量、しかもJSだけでこういうアプリが作れるのはちょっとした衝撃でした。
</p>
<h3>サーバ（node.websocket.js/modules/wb.js）</h3>
<pre class="source"><code>var Module = this.Module = function(){
	// グローバルにしとくと楽
	sys = require('sys');
};

Module.prototype.onData = function(data, connection) {
	// 初期化
	if (data == 'start'){
	
		// 定期的にファイルをcatして変わってたらクライアントに送る
		this.interval = setInterval(function(){
			var self = this;
			sys.exec('cat temp').addCallback(function(stdout, stderr) {
				if (self.temp != stdout) {
					connection.send(stdout);
				}
				self.temp = stdout;
			});
		}, 100);
		
	} 
	// データを受信したらtempファイルに書き込む（超脆弱！！）
	else {
		sys.exec('echo "' + data +'" > temp');
	}
};

// 後始末
Module.prototype.onDisconnect = function(connection){
	clearInterval(this.interval);
};</code></pre>

<h3>クライアント（apache/htdocls/wb.html）</h3>
<pre class="source"><code>&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
	&lt;title&gt;whiteboard demo&lt;/title&gt;
	&lt;style&gt;
canvas {
	border: 1px solid black;
	position: relative;
}
	&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;h1&gt;whiteboard demo&lt;/h1&gt;

&lt;canvas width="300" height="200"&gt;&lt;/canvas&gt;&lt;br /&gt;
&lt;input type="button" value="clear" /&gt;

&lt;script&gt;

// node.websocket.js/modules/wb.jsに繋ぐ
var webSocket = new WebSocket('ws://localhost:8000/wb');

/* お絵かき処理ここから */

var canvas = document.getElementsByTagName('canvas')[0];
var ctx = canvas.getContext('2d');

var isDraw = false;
var x, y;

canvas.addEventListener('mousedown', function(e) {
	ctx.moveTo(x, y);
	isDraw = true;
}, 'false');

canvas.addEventListener('mousemove', function(e) {
	x = e.layerX;
	y = e.layerY;
	if (isDraw) {
		ctx.lineTo(x, y);	
		ctx.stroke();
	}
}, 'false');

canvas.addEventListener('mouseup', function(e) {
	isDraw = false;
	webSocket.send(canvas.toDataURL());
}, 'false');

/* お絵かき処理ここまで */

// サーバ側に初期化を知らせる
webSocket.onopen = function(event){
	webSocket.send('start');
};

// データ受信時は問答無用でcanvasを更新
webSocket.onmessage = function(event){
	var img = new Image();
	img.onload = function() {
		ctx.clearRect(0, 0, canvas.width, canvas.height);
		ctx.drawImage(img, 0, 0);
	};
	img.src = event.data;
};

// 白紙に戻す
document.querySelector('input[value=clear]').addEventListener('click', function() {
	ctx.clearRect(0, 0, canvas.width, canvas.height);
	webSocket.send(canvas.toDataURL());
}, 'false');

&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
]]>
			</description>
			<link>http://blog.bornneet.com/Entry/268/</link>
			<pubDate>Sun, 31 Jan 2010 04:32:04 GMT</pubDate>
		</item>
		<item>
			<title>HTML5に追いつこう！Pure JSでWeb Socketsを動かしてみる</title>
			<description>
			<![CDATA[<p>
HTML5の仕様も、コミュニティの皆さんも動きが速すぎてすっかり置いてかれています。<br />
とはいえ、HTML5は勉強しておいて絶対損はないはずなので、<br />
マイペースで頑張りたいと思います。。<br />
<br />
そんな中、今日、<br />
<a href="http://d.hatena.ne.jp/download_takeshi/20091215/1260903057" class="external" target="_blank" title="新しいウィンドウで開きます">噂のnode.websocket.jsでサーバサイドJSとHTML5 WebSocketを体験してみたの巻 - ダウンロードたけし（寅年）の日記</a><br />
<a href="http://blog.new-bamboo.co.uk/2009/12/7/real-time-online-activity-monitor-example-with-node-js-and-websocket" class="external" target="_blank" title="新しいウィンドウで開きます">Real time online activity monitor example with node.js and WebSocket @ Bamboo Blog</a><br />
なんていう素敵な記事を見つけました。<br />
Apacheは好きだけどPythonはちょっと・・・な僕でもこれならできるはず！と<br />
初めてのWeb Socketsに挑戦してみました。<br />
<br />
というわけで、改めてお勉強。<br />
<br />
まずはAPI仕様。（プロトコルは長いし英語なのでまた今度）<br />
<a href="http://www.html5.jp/trans/w3c_websockets.html" class="external" target="_blank" title="新しいウィンドウで開きます">W3C - 『The Web Sockets API』日本語訳 - HTML5.JP</a><br />
うん、これだけじゃわからんですね^^<br />
<br />
デモとか見て勉強しよう。<br />
<br />
<a href="http://blog.livedoor.jp/kotesaki/archives/1355651.html" class="external" target="_blank" title="新しいウィンドウで開きます">こてさきAjax:apache+mod_pywebsocetを用いたliteなwebsocketsチャットサンプル - livedoor Blog（ブログ）</a><br />
pywebsocketの例。サーバサイドの処理の説明がわかりやすいです。<br />
<br />
<a href="http://blog.livedoor.jp/kotesaki/archives/1357005.html" class="external" target="_blank" title="新しいウィンドウで開きます">こてさきAjax:apache + web sockets (pywebsocket) tips #0 - livedoor Blog（ブログ）</a><br />
<a href="http://blog.livedoor.jp/kotesaki/archives/1362401.html" class="external" target="_blank" title="新しいウィンドウで開きます">こてさきAjax:lite websocket チャットサンプルを更新しました。 - livedoor Blog（ブログ）</a><br />
引き続きpywebsocket。<br />
Origin checkとHeartBeatがキーワードというかいつかハマリそうな予感。<br />
覚えておこう。<br />
<br />
<a href="http://blog.livedoor.jp/kotesaki/archives/1369902.html" class="external" target="_blank" title="新しいウィンドウで開きます">こてさきAjax:websocketでは、encodeURIComponet()は使うべきではない - livedoor Blog（ブログ）</a><br />
データはUTF-8で送受信するので、encodeURI()しなくても良いと、ふむふむ。<br />
<br />
なんとなくイメージが湧いてきた。<br />
プレゼン資料とかも漁ってみる。<br />
（やっぱシーケンスがあるとわかりやすいですね！）<br />
<br />
<a href="http://docs.google.com/present/view?id=dddvzhrc_3frv8djhr" class="external" target="_blank" title="新しいウィンドウで開きます">WebSocketでリアルタイムWeb</a><br />
かなり噛み砕いた説明でわかりやすいです。<br />
<br />
<a href="https://docs.google.com/present/view?id=0AeBWWQgzzR2xZGNyM3h3MnNfOWM4NXpocDN2&hl=en" class="external" target="_blank" title="新しいウィンドウで開きます">100113_opera webkit勉強会(websocket)</a><br />
<a href="http://blog.livedoor.jp/kotesaki/archives/1377879.html" class="external" target="_blank" title="新しいウィンドウで開きます">こてさきAjax:websocket関連の説明png - livedoor Blog（ブログ）</a><br />
図がいっぱい。素敵。<br />
<br />
<a href="http://journal.mycom.co.jp/special/2009/html5-2/009.html" class="external" target="_blank" title="新しいウィンドウで開きます">【特集】詳解! HTML 5と関連APIの最新動向 - Webアプリ開発編 (10) Web Sockets | エンタープライズ | マイコミジャーナル</a><br />
Kaazingを使ったデモ。初心者を切り捨てない感じで助かります。<br />
<br />
そろそろ良いかな…よし、やってみよう！
</p>
<h3>node.jsのインストール</h3>
<p>
<a href="http://nodejs.org/" class="external" target="_blank" title="新しいウィンドウで開きます">node.jsのサイト</a>からnode-v0.1.26.tar.gzをダウンロード。<br />
<pre class="source"><code>cd node-v0.1.26/
./configure —prefix=/Users/t/node.js/
※ prefix指定はできない？

./configure
※ 諦めてそのままインストールする。

make
sudo make install

which node
/usr/local/bin/node

</code></pre>
<p>何事もなく終了。<br />
※ ホントはユーザ権限でインストールしたかったけど・・・</p>

<h3>Hello, node.js</h3>
<p>とりあえず、指定ディレクトリをlsして返すプログラムを書いてみました。<br />
queryから取ろうと思ったけど、うまく動かないメソッドとかもあったのでやめときました。</p>
<pre class="source"><code>vi ls.js

var sys = require('sys');

var filename = process.ARGV[2];

var http = require("http");
http.createServer(function(req, res){
	res.sendHeader(200,{"Content-Type": "text/html; charset=UTF-8"});
	sys.exec('ls -alF ' + filename).addCallback(function _exec(stdout, stderr) {
		res.sendBody(stdout);
		res.finish();
	});  
}).listen(8000);
:wq

<strong>node ls.js .</strong>

[別ターミナルで]
telnet localhost 8000
GET / HTTP/1.1
host:localhost

HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Transfer-Encoding: chunked

1cc
total 80
drwxr-xr-x   9 t  staff   306  1 25 00:17 ./
drwxr-xr-x+ 47 t  staff  1598  1 24 23:27 ../
-rw-r--r--@  1 t  staff  6148  1 25 00:17 .DS_Store
-rwxr-xr-x@  1 t  staff   304  1 24 23:42 example.js*
-rwxr-xr-x@  1 t  staff   329  1 24 23:49 log.txt*
-rwxr-xr-x@  1 t  staff   334  1 25 00:17 ls.js*
drwxr-xr-x@ 20 t  staff   680  1 24 23:35 node-v0.1.26/
drwxr-xr-x   5 t  staff   170  1 25 00:17 old/
-rwxr-xr-x@  1 t  staff   601  1 24 23:50 tail.js*
こんな感じで返ってきます。
</code></pre>
<h3>Hello, Web Sockets</h3>
<p>ようやく本題・・・ですが眠いので既存サンプルを動かすだけにしときます。</p>

<pre class="source"><code>git clone git://github.com/Guille/node.websocket.js.git
<a href="http://github.com/guille/node.websocket.js/" class="external" target="_blank" title="新しいウィンドウで開きます">node.websocket.js at master</a>をチェックアウト

cd node.websocket.js

cp test/test.html ~/apache/htdocs/
apache上にクライアントを配置 

vi ~/apache/htdocs/test.html
<strong>var webSocket = new WebSocket('ws://localhost:8000/time');</strong>
ポートを8000に変更（apacheと競合してたので）

node runserver.js --port="8000"
Web Socketsサーバを起動

apachectl start
apacheを起動（8080を使ってます）

</code></pre>
<p>Google Chrome 4+からlocalhost:8080/test.htmlにアクセスすると、<br />
時刻がリアルタイムで更新されるサンプルが表示されます。<br />
（地味ですが確かにpullではなくpushで実現されています。）<br />
<br />
<img src="http://file.blog.bornneet.com/hello_websocket.png" alt="" />
</p>

<h3>まとめ</h3>
<p>
思っていたより手軽に触れそうです。<br />
僕程度のスキルでも2時間程度で動かすとこまではできました。<br />
<br />
さて、なんか面白いことできないかなー。
</p>]]>
			</description>
			<link>http://blog.bornneet.com/Entry/267/</link>
			<pubDate>Sun, 24 Jan 2010 15:51:48 GMT</pubDate>
		</item>
		<item>
			<title>今更ながら、人工無脳なTwitterボット作ってみた</title>
			<description>
			<![CDATA[<p>
Perlの勉強の為、久々に人工無脳を作ってみました。<br />
<br />
説教っぽく聞こえなくもない言葉を30分に1回つぶやきます。<br />
<br />
<a href="http://twitter.com/bornneet/" class="external" target="_blank" title="新しいウィンドウで開きます">迷言ボット (bornneet) on Twitter</a><br />
<br />
興味のある方はfollowしてみて下さい。<br />
精度は全然ですが、まぐれで良いこというかもしれませんよ^^<br />
<br />
<br />
最初は、以下の記事を参考にNet::Twitterでやろうとしたのですが、<br />
Macにうまくインストールできなかったので、断念。<br />
<a href="http://www.otchy.net/20090629/making-of-twitter-bot-1/" class="external" target="_blank" title="新しいウィンドウで開きます">Twitter ボットの作り方 Perl 編 (1) – OTCHY.NET</a><br />
<br />
cpanをupdate（cpan > install Bundle::CPAN）とかやってみるも、状況変わらず。<br />
（<a href="http://technolo-walk.blogspot.com/2009/08/perlnettwittercpan.html" class="external" target="_blank" title="新しいウィンドウで開きます">テクノロ散策: PerlでNet::Twitterがインストールできない時はcpanをアップデート</a>）<br />
<br />
xreaにはNet::Twitterが入ってるので、使いたかったんですが、<br />
仕方なく生Perlで書くことにしました。<br />
<br />
参考にしたのはこちらの3記事。<br />
<a href="http://blog.livedoor.jp/dankogai/archives/51220581.html" class="external" target="_blank" title="新しいウィンドウで開きます">404 Blog Not Found:API - Twitterfeed から Hatena::Bookmark Web Hookへ</a><br />
<a href="http://www.naney.org/diki/dk/Net::Twitter.html" class="external" target="_blank" title="新しいウィンドウで開きます">nDiki: Net::Twitter - Net::OAuth を使って Twitter からフィードを取得 (2009-12-30)</a><br />
<a href="http://www.akatsukinishisu.net/itazuragaki/perl/basic_auth_post_by_lwp_useragent.html" class="external" target="_blank" title="新しいウィンドウで開きます">LWP::UserAgentで基本認証とPOSTを - 徒書</a><br />
<br />
最後の最後、xreaでの動作確認でさらにはまりました。<br />
Storableに「Byte order is not compatible at blib/lib/Storable.pm」と言われてもうお手上げ。<br />
<br />
またまた先人の力をお借りして何とか解決しました。<br />
（storeを使わず、nstoreを使用）<br />
<a href="http://blog.livedoor.jp/dankogai/archives/50490051.html" class="external" target="_blank" title="新しいウィンドウで開きます">404 Blog Not Found:perl - 勝手に添削 - Storable</a><br />
<a href="http://www.xdelta.net/wiki/WiKicker.html#h5" class="external" target="_blank" title="新しいウィンドウで開きます">Perl  5.6.2→5.8.7移行メモ</a><br />
<br />
いやぁ、相変わらず、Perlには慣れませんねぇ…orz<br />
<br />
※ おまけでxrea無料版ではcronが動かせないという罠も。（何を今さら）<br />
　 というわけでcore serverのアカウントで稼働させてます。
</p>]]>
			</description>
			<link>http://blog.bornneet.com/Entry/266/</link>
			<pubDate>Sun, 24 Jan 2010 10:37:03 GMT</pubDate>
		</item>
		<item>
			<title>Firefox3.6がリリースされたので、canvas作品をFile API(とDrag&amp;Drop)に対応させてみた</title>
			<description>
			<![CDATA[<p>
お久しぶりです。<br />
<br />
僕がインターネットのない生活を送っている間に、<br />
待望のFirefox3.6がリリースされましたね！<br />
<br />
これでFirefoxがターゲットのサイトなら、FireAPIを使い放題です！！<br />
（今まではβ版だったので、開発者しか使ってませんでしたからね・・・）<br />
<br />
というわけで、以下の2作品をFile API対応させときました。<br />
<br />
ダイアログを使うか、選択欄にdrag&dropすればローカルファイルを指定できます。<br />
<br />
<a href="http://tnantoka.net/canvas/editor/">錯覚エディター by HTML5 Canvas</a><br />
<a href="http://tnantoka.net/canvas/glass/">canvasで画像拡大鏡</a><br />
<br />
何かたまにおかしくなりますが、サンプルということで許して下さい^^<br />
あと、巨大ファイルや画像じゃないファイルを指定すると壊れますのでご注意を。<br />
<br />
File API、面白いので皆さん是非試してみて下さい！<br />
<br />
※ 以前File APIの簡単な使い方をLTしたのでよろしければどうぞ。
</p>
<div style="width:425px;text-align:left" id="__ss_2750248"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/tnantoka/file-api-in-firefox36" title="File API in Firefox3.6">File API in Firefox3.6</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=mozillatokyo-091219104028-phpapp02&stripped_title=file-api-in-firefox36" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=mozillatokyo-091219104028-phpapp02&stripped_title=file-api-in-firefox36" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;">View more <a style="text-decoration:underline;" href="http://www.slideshare.net/">presentations</a> from <a style="text-decoration:underline;" href="http://www.slideshare.net/tnantoka">tnantoka</a>.</div></div>
]]>
			</description>
			<link>http://blog.bornneet.com/Entry/265/</link>
			<pubDate>Fri, 22 Jan 2010 10:04:44 GMT</pubDate>
		</item>

		</channel>
	</rss>