前回、前々回と気になっていたうさちゃんのメモリマップを調べて少しスッキリしたので、HTTPデーモンねたへと戻りました。今回は改めてということで最小構成、動的なページが一切ないスタティックなHTMLと画像のみをサーバするサンプルプログラムを眺めてみたいと思います。これだけなら簡単?ホントか?
※「うさちゃんと一緒」投稿順indexはこちら
※うさちゃん、Rabbit4000は、Z80との機械語レベルでの互換性を「ほぼほぼ」維持しつつ大拡張した「最強の」(個人の感想です)8ビット機であります。8ビットのくせに?Ethernetインタフェースなど搭載してネットワークに対応してます。Dynamic Cという、ほぼほぼ標準C(といってもANSI C90)ではあるけれど、独自拡張しまくりのCコンパイラで開発をいたします。Rabbit4000のドキュメント類はこちら
HTTPサーバ(スタティック)の最小構造
今回は、Dynamic C付属のサンプルプログラムの中から、その名も STATIC.C なるプログラムを読んでいきます。そのものズバリ、静的なHTMLページのみを返すサーバプログラムの雛形です。
プログラムの骨子に入るまえに大事なオマジナイが以下に
#memmap xmem #use "dcrtcp.lib" #use "http.lib"
すべてDynamic C独自拡張のディレクティブです。 #memmap xmem で拡張メモリであるXMEMに関数達を置くぞ、と宣言しとられます。メモリマップについては前回、前々回をご参照くだされ。
その次の #use は、通常の #include と似た意味を持つライブラリを取り込むためのディレクティブです。通常の #include を使ってヘッダファイルをインクルードする、という方法も可能ではあるみたい(試してない)です。しかし、うさちゃんでは、もっぱら #use を使って “.lib” という拡張子のライブラリファイル(単なるヘッダではなく実体コードも含まれている)を取り込むスタイルです。
そのうち http.lib は単独のライブラリで、今回使用するライブラリ関数のうち http関係のものが含まれています。それにたいして
dcrtcp.lib
の方は、ネットワーク関係を使う場合にはまず最初に必ず取り込むライブラリです。dcrtcp.lib自体にはほとんど実体がなく、dcrtcp.libの中で他の多数のライブラリを呼んでいるファイルです。ネットワーク関係の基本的な関数がこれで使えるようになります。
さて、HTTPサーバの最小構成を切り取ると以下です。シンプル!
sock_init_or_exit(1); http_init(); tcp_reserveport(80); while (1) { http_handler(); }
-
- sock_init_or_exit(1);
うさちゃんのマニュアル類では、sock_init()の方が説明されていて、失敗したら停止するところまで含まれるsock_init_or_exit(1)は説明されてません。いずれにせよ、sock_initは必須です。TCP/IPプロトコルスタックの初期化を行う関数のようです。ARP/TCP/UDP/DNSみな初期化されるみたいです。成功するかエラーとなるまで帰ってこない関数。sock_init()で呼び出した場合、成功、不成功を返してきますが、不成功なら止めるしかないので、sock_init_or_exit(1)の方が実用的かと。
-
- http_init();
httpサーバーの初期化関数です。呼び出しは sock_init() の成功後でなけらばならず、また、後で出てくる http_handler() を呼び出す前でなければならないと。
-
- tcp_reserveport(80);
TCPが反応するポート番号を記憶するための関数みたいです。今回はHTTPサーバであるので、お馴染み80番ポートを確保しています。
-
- http_handler()
HTTPリクエストをパースし、必要であれば他のハンドラを呼び出す、これぞHTTPデーモンの根元です。他のハンドラとはhtmlハンドラ、shtmlハンドラ、ユーザ指定のCGIハンドラなどみたいです。RTOSを使わない場合は、ループ内部で呼びだし続ける必要があります。通常は、ループ内部に必要なIO処理の呼び出し関数などと並べて回す形になるみたい。最低1秒間に10回とな。
今回使用しているのは、ライブラリ内のデフォルトのハンドラです。タイムアウト処理なども含めたHTTPのステートマシン的なもの。上書き可能ではあります(でも複雑だから私はそのまま使いたいデス。)
サーバ構成のための準備的な?
以下は「スタティックな」HTTPサーバとして動作させるための設定類です。まずは、IPアドレスの指定。
#define TCPCONFIG 1 に続けて以下のようにスタティックに指定しています。DHCPとか使用する場合はまた別。
#define TCPCONFIG 1 #define _PRIMARY_STATIC_IP "192.168.2.59" #define _PRIMARY_NETMASK "255.255.255.0" #define MY_GATEWAY "192.168.2.1" #define MY_NAMESERVER "192.168.2.1"
念のため、タイムゾーンの設定も。
#define TIMEZONE 9
再び登場したXMEMです。#ximport で第1引数で指定されたファイル名のファイル内容(バイナリ)をXMEMにロードし、その先頭番地を第2引数に格納します。うさちゃんは外部ファイルシステムも使えるのでHTMLファイルをそちらに置くのであればXMEM使わないと思います。現状外部ファイルシステムは接続していないのでXMEMの隅をストレージのように使ってます。
#ximport "static.html" index_html #ximport "rabbit1.gif" rabbit1_gif
MIMEタイプの設定テーブルが以下に。HTTPデーモン内部で拡張子を見てその動作を切り替えるために使われているみたいです。ホントか?
SSPEC_MIMETABLE_START SSPEC_MIME(".html", MIMETYPE_HTML), SSPEC_MIME(".gif", MIMETYPE_GIF) SSPEC_MIMETABLE_END
以下がリソーステーブルです。今回は静的なサーバなので、ルートに index_html(さきほどの ximport でバイナリロードしたファイル)をおき、同様にgifファイルも配置しています。
SSPEC_RESOURCETABLE_START SSPEC_RESOURCE_XMEMFILE("/", index_html), SSPEC_RESOURCE_XMEMFILE("/rabbit1.gif", rabbit1_gif) SSPEC_RESOURCETABLE_ENDど
動作確認
コンパイル(配置はRAM指定)してRUNすると、うさちゃん標準出力ウインドウが現れます。ネットワークインタフェースが起動し動いているみたいです。
さて外部のブラウザからうさちゃんのIPアドレスにhttp接続してみたところが冒頭のアイキャッチ画像に。「静的なコンテンツ」表示されとります。動作OKっと。That was EASYだって。確かに簡単でした。