[BlueLeaf1336]> PROGRAM>

WEBサーバを作ろう-001

historyTOP

2003/07/31:作成
2003/08/02:整理
2003/08/03:サーバの要求受信から応答送信までをスレッド化
2003/08/04:サーバの待ち自体をスレッド化

referenceTOP

C/C++300の技(以下テキストと呼称する)
http://www.asahi-net.or.jp/~nk2w-ishr/
http://hp.vector.co.jp/authors/VA009712/take/delphi/kabesys.htm

overviewTOP

WEBサーバです。テキストのやっているとおりにやります。 ただ、Delphiでやります。いつまでかかるのか全くわかりません。 タイトルもそのままパクルことにします。

では行きます。

P36:057 具体的なクライアントのコードはどうなるのか?TOP

長いのでダウンロードで。20030731client057.zip(3,009bytes)

実行した感じはこんなのです。意外にうまくいきました(とはいえテキストでは初歩もええとこみたいな扱いですが...)。

20030731client057

次はサーバです。

P37:058 具体的なサーバのコードはどうなるのか?TOP

長いのでダウンロードで。20030731server058.zip(3,132bytes)

まず、作ったサーバを起動し「待ち」状態にしました。 その後、さっき作ったクライアントを起動し「要求」を送り付けました。

サーバは、コードを見てもらえればわかるのですがスレッドにしていないため、要求待ちを永久ループにはできないので、 「待ち」に入ってから5回だけ要求を受け取ると「待ち」を解除するようにしています。

まず、サーバ側です。この図は「待ち」に入った後クライアントからの要求を5回受けて「待ち」を解除したあとの状態です。 「GET...」がクライアント(=さっき作ったクライアント)からの要求で、「<html>...」が送り返したHTMLです。 「---...---」で区切られた部分が1回の要求・回答のセットです。2回目の要求が見たこと無いものになっていますが、何でしょう?

20030731server058

次に、クライアント側です。こちらはサーバ側とは違い、1回ごとに受け取った内容をクリアしています。 とはいえ、どうせ同じHTMLを受け取るので関係無いですが。

20030731client057

とにかく、意外と順調です。1対1なら...。あとはスレッド化です。

整理してみましたTOP

長いのでダウンロードで。20030802svrclnt.zip(5,936bytes)

サーバ/クライアントともに、基本的には順番に関数を呼び出しているだけです。 ですが、関数を呼び出すための下準備が必要です。たとえば構造体を空にするとか、構造体のサイズをセットするとか。 これらを毎回書くのも邪魔くさいので、それぞれ使用する関数ごとに対応する呼び出し用の関数を準備しました。
で、iNet.pasというユニットにまとめました。 最終的にはクラスにしたい感じなので、内部で呼び出しているWinsockの関数と同名にしています。(ちょっと微妙ですが...)
それから、サーバとクライアントをひとつのプログラムにまとめました。 具体的には、PageControlを使用して、1ページ目(のボタン)がサーバで、2ページ目(のボタン)がクライアントです。

下は、サーバの図です。とはいっても、最初のものと見た目は全く変わってませんが。(ただ、返却用のHTMLに問題があったので直してます。)
使い方としては、まずサーバのボタンを押して、待ち状態にします。

20030802svrclnt

下は、クライアントの図です。このページのボタンを押すと、(サーバ)が待っていれば返事が返ってくるはずです。
上のサーバの図は、クライアントとの何回かのやりとりを行った状態です。

20030802svrclnt

次は、Internet Explorerとのやりとりを行った状態のサーバプログラムです。 なんやらいろいろと送られてきています。 手製のへっちょこクライアントはこのうちの「GET」行だけをサーバに送っていたわけです。

Internet Explorer 6.0

最後が、Internet Explorerの画面です。なんか嬉しいです。

20030802svrclnt

P49:081 スレッドを使ってサーバを実装するには?TOP

長いのでダウンロードで。20030803thread.zip(14,773bytes)

ダミーのHTMLコードでは面白くないので、代わりにyahooのトップページを返すことにしたらEUCだったのでEUCをSJISに変換する単に、jconvert.pas(作者のサイトにたどり着けずDelphianWorldからもダウンロードできなかったため、しかたなく「日本語プログラム言語ひまわり」のソースコードに含まれているものを勝手に使っています)を使ったため突然サイズがでかくなりました(長っ)。
あと、yahooのトップページを返すために、yahooのトップページをダウンロードする必要があるので、WinInet.pasをusesに加えてネットで拾ったダウンロードコードを追加しました。

スレッド化しただけなので、その性質上外見は変わらないのですが、面白くないので少しだけ変更しました。

まず、サーバ側です。
クライアントに返却するのが固定文字列では面白くないので、待ち受け開始時に指定したページをわざわざダウンロードしてきてそれを返却するように変更しました。 もし、指定したページのダウンロードに失敗したら以前と同じような固定文字列を返却します。
それから待ち受けを無限ループに変更しました。よって、終了させるには強制終了しかありません。
スレッド化したことで以前のように、受けた内容・返却した内容をうまく表示できなく(原理的にできないということではなく技術的にできてないだけだと思います)なったので、代わりにメモリ使用状況を表示するようにしました。
起動時と、送受信スレッド実行時に表示が更新されるはずです。
最後に、指定したページをダウンロードするように変更したことで文字コードの問題が出てきたため、とりあえずSJISに変更してクライアントに返却します。 ただし、googleのトップページはunicodeでかかれているようでもうひとつうまくいきません。

20030803thread

それからクライアントですが、こちらは別に何も変えてません。ボタンのキャプションぐらいです。

20030803thread

最後におまけのInternet Explorerの画面です。yahooって相対パスで書いてないようで、画像も含めてキレーに表示されてます。あ..ちょっと化けてる。

Internet Explorer 6.0

to be continued..TOP

WEBサーバを作ろう-002へ。いつになることやら。

もっかいだけ修正TOP

長いのでダウンロードで。20030804thread.zip(7,840bytes)

やっぱり強制終了しかないのはアレなのでサーバの待ち自体をスレッド化しました。 この修正で今までのようにボタン押したら強制終了までイベントハンドラから出ずに待ちっぱなしということがなくなるため、ボタンクリックに全部の処理を書くわけには行かなくなります。
まず、フォームのコンストラクタで待ちスレッドをつくり、スレッドのコンストラクタでbind/listenするように変更しました。この時点では待ちスレッドは一時停止状態です。 次に、ボタンクリックで一時停止/再開を切り替えるようにしました。最後に、フォームのデストラクタで待ちスレッドを解放するようにしました。
ただ、acceptがいったん呼んだらクライアントからの要求が無いかぎり帰ってこないはずなのに、予想以上にあっさり終了できる(=待ちスレッドの解放があっさり)なのが気になります。が、気にしても仕方が無いのでほっときます。

ところで、今までどおり、サーバとクライアントが同一EXEなので、複数起動するとみんながみんなbind使用とすることになります。 で、失敗します。同じポートはただ1つのサービスによってのみ使用できるからです。 なので、ここでは、サーバスレッドの起動に成功したらサーバとして、失敗したらクライアントとして動作するようにしています。

勝手にSJISに変換するのも止めました。サーバがそんなことしちゃいかん。

EOFTOP