HTML文書にGIFを埋め込んでみた [ColdFire V2]
付録基板のhttpサーバは、SilentMoonというオペレーティング・システム上で動作していることがわかっています。 どのくらいの能力を持っているのか、確認してみましょう。
HTML文書は、これだ
HTML文書として用意したのは、これです。
<html><head> <title>RiverSea</title> <style> table.board {text-align:center;} table.board td {width:40px;height:40px;background:#0F0;} </style> </head><body> <h1 style="text-align:center;">RiverSea</h1> <form action="RiverSeaAction.htm" style="text-align:center;"> <table cellpadding="10" style="margin:0 auto;"> <td> <table border="1" cellpadding="2" cellspacing="1" class="board"> <tr><th colspan="14"/></tr> <tr> <th rowspan="12"/><th/><th rowspan="12"/> <th>A</th><th>B</th><th>C</th><th>D</th> <th>E</th><th>F</th><th>G</th><th>H</th> <th rowspan="12"/> </tr> <tr><th/><th colspan="8"/></tr> <tr><th>1</th> <td/><td/><td/><td/><td/><td/><td/><td/> </tr> <tr><th>2</th> <td/><td/><td/><td/><td/><td/><td/><td/> </tr> <tr><th>3</th> <td/><td/><td/><td/><td/><td/><td/><td/> </tr> <tr><th>4</th> <td/><td/><td/> <td><img src="W.gif"/></td> <td><img src="B.gif"/></td> <td/><td/><td/> </tr> <tr><th>5</th> <td/><td/><td/> <td><img src="B.gif"/></td> <td><img src="W.gif"/></td> <td/><td/><td/> </tr> <tr><th>6</th> <td/><td/><td/><td/><td/><td/><td/><td/> </tr> <tr><th>7</th> <td/><td/><td/><td/><td/><td/><td/><td/> </tr> <tr><th>8</th> <td/><td/><td/><td/><td/><td/><td/><td/> </tr> <tr><th colspan="14"/></tr> </table> </td> </form> </body></html>
GIFファイルは、これだ
表示できたかな?
ブラウザでHTML文書を呼び出すと文書本体もGIF画像もうまく表示されました。
パケット・モニタで通信状況を観測する
それでは、どんな通信が飛んでいるのかをパケット・モニタで確認します。
#1 0.000000 192.168.1.2 192.168.1.10 TCP 1538 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #2 0.000372 192.168.1.10 192.168.1.2 TCP 80 > 1538 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #3 0.000448 192.168.1.2 192.168.1.10 TCP 1538 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0
まずは、3ウェイ・ハンドシェイクから。
#4 0.007597 192.168.1.2 192.168.1.10 TCP 1538 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=429 HTTP GET /RiverSeaTemplate.htm HTTP/1.1 #5 0.008578 192.168.1.10 192.168.1.2 TCP 80 > 1538 [ACK] Seq=1 Ack=430 Win=1454 Len=0 #6 0.012538 192.168.1.10 192.168.1.2 TCP 80 > 1538 [PSH, ACK] Seq=1 Ack=430 Win=1454 Len=1377 HTTP HTTP/1.1 200 OK (text/html)
まず、#4でブラウザからHTML文書が要求されます。 ColdFireは、#5で一旦受信確認を送り、続いて#6で要求されたHTML文書を送ります。
#7 0.072102 192.168.1.2 192.168.1.10 TCP 1538 > 80 [PSH, ACK] Seq=430 Ack=1378 Win=16616 Len=435 HTTP GET /W.gif HTTP/1.1 #8 0.073084 192.168.1.10 192.168.1.2 TCP 80 > 1538 [ACK] Seq=1378 Ack=865 Win=1454 Len=0 #9 0.073135 192.168.1.10 192.168.1.2 TCP 80 > 1538 [FIN, ACK] Seq=1378 Ack=865 Win=1454 Len=0 #10 0.073193 192.168.1.2 192.168.1.10 TCP 1538 > 80 [ACK] Seq=865 Ack=1379 Win=16616 Len=0 #11 0.075050 192.168.1.2 192.168.1.10 TCP 1538 > 80 [FIN, ACK] Seq=865 Ack=1379 Win=16616 Len=0 #12 0.075376 192.168.1.10 192.168.1.2 TCP 80 > 1538 [ACK] Seq=1379 Ack=866 Win=1454 Len=0
続いて、ブラウザは、#7で同じポート番号を使い、GIFファイル W.gif を要求します。 これに対して、ColdFireは、#8で受信確認を送るのですが、すぐに#9で切断要求を出します。 これは、#4から#6でHTML文書の送信が終了したためであると思われます。 以下、#12まででこのコネクションは、終了します。
#13 0.080873 192.168.1.2 192.168.1.10 TCP 1541 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #14 0.081243 192.168.1.10 192.168.1.2 TCP 80 > 1541 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #15 0.081336 192.168.1.2 192.168.1.10 TCP 1541 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #16 0.083014 192.168.1.2 192.168.1.10 TCP 1542 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #17 0.083376 192.168.1.10 192.168.1.2 TCP 80 > 1542 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #18 0.083444 192.168.1.2 192.168.1.10 TCP 1542 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0
ブラウザは、再度GIFファイルを要求するためにコネクションを試みます。 ところが、今度は様子が違います。 ポート番号1541と1542の二つのポートからほぼ同時にコネクションを張ろうとしています。 ColdFireも、#14と#17で双方のポートに対してコネクションを張ったように見えます。 これがうまく働けば、ColdFireも「並行サーバ」であると言えるはずです。
#19 0.085585 192.168.1.2 192.168.1.10 TCP 1541 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=435 HTTP GET /W.gif HTTP/1.1 #20 0.086568 192.168.1.10 192.168.1.2 TCP 80 > 1541 [ACK] Seq=1 Ack=436 Win=1454 Len=0 #21 0.087908 192.168.1.10 192.168.1.2 TCP 80 > 1541 [PSH, ACK] Seq=1 Ack=436 Win=1454 Len=425 HTTP HTTP/1.1 200 OK (GIF89a)
ブラウザは、まず#19でGIFファイル W.gif を要求します。 ColdFireも#20と#21でこれに応えます。
#22 0.091548 192.168.1.2 192.168.1.10 TCP 1542 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=435 HTTP GET /B.gif HTTP/1.1 #23 0.092544 192.168.1.10 192.168.1.2 TCP 80 > 1542 [ACK] Seq=1 Ack=436 Win=1454 Len=0 #24 0.093880 192.168.1.10 192.168.1.2 TCP 80 > 1542 [PSH, ACK] Seq=1 Ack=436 Win=1454 Len=415 HTTP HTTP/1.1 200 OK (GIF89a)
ブラウザは、続いて#22でGIFファイル B.gif を要求します。 ColdFireは、#23と#24でこれに応えます。
#25 0.192704 192.168.1.2 192.168.1.10 TCP 1541 > 80 [ACK] Seq=436 Ack=426 Win=16191 Len=0 #26 0.193082 192.168.1.10 192.168.1.2 TCP 80 > 1541 [FIN, ACK] Seq=426 Ack=436 Win=1454 Len=0 #27 0.193163 192.168.1.2 192.168.1.10 TCP 1541 > 80 [ACK] Seq=436 Ack=427 Win=16191 Len=0 #28 0.293303 192.168.1.2 192.168.1.10 TCP 1542 > 80 [ACK] Seq=436 Ack=416 Win=16201 Len=0 #29 0.293723 192.168.1.10 192.168.1.2 TCP 80 > 1542 [FIN, ACK] Seq=416 Ack=436 Win=1454 Len=0 #30 0.293837 192.168.1.2 192.168.1.10 TCP 1542 > 80 [ACK] Seq=436 Ack=417 Win=16201 Len=0 #31 8.846858 192.168.1.2 192.168.1.10 TCP 1542 > 80 [FIN, ACK] Seq=436 Ack=417 Win=16201 Len=0 #32 8.847122 192.168.1.2 192.168.1.10 TCP 1541 > 80 [FIN, ACK] Seq=436 Ack=427 Win=16191 Len=0
二つのGIFファイルを送受信する間、二つのポートは共にコネクションされたままの状態です。 ブラウザが#25でポート1541の受信確認を送ると、#26でColdFireが切断を要求します。 これに対して、ブラウザは、#27と#32で切断を受諾しますが、それに対してColdeFireからは最後のACKが返ってきません。 これは、おかしいな。 ブラウザの切断受諾に8秒以上時間がかかっているのも妙です。
ブラウザは、#25のポート1541の受信確認の0.1秒後に#28でポート1542の受信確認を送ります。 ColdFireは、#29で切断を要求し、ブラウザが#30と#31で切断を受諾します。 これに対してもColdFireからは最後のACKが返ってきませんでした。
#33 11.257293 192.168.1.2 192.168.1.10 TCP 1542 > 80 [FIN, ACK] Seq=436 Ack=417 Win=16201 Len=0 #34 11.257325 192.168.1.2 192.168.1.10 TCP 1541 > 80 [FIN, ACK] Seq=436 Ack=427 Win=16191 Len=0
そのため、ブラウザは、双方のポートから最後の"FIN"を再送し続けるのですが、もうColdFireは、返答しません。 やっぱり、おかしいな。
本日の考察
- ブラウザが、複数のGETリクエストを同一のポートから出した、つまりコネクションを使い回しした場合、ColdFireは、二回目のリクエストに受信確認を出した後すぐにコネクションを切断してしまう。
- ColdFireのhttpサーバは、ブラウザからの要求に対して少なくとも二つコネクションを張ることが出来る。
- 複数のコネクションが張られたとき、コネクションの切断に必要なhttpサーバからのACKをColdFireは返さない。
TCP/IPの仕様として、どんな振る舞いがふさわしいのか理解していないので、ブラウザとColdFireのhttpサーバのどちらに問題があるのか、私には判断出来ません。
参考文献
Interface (インターフェース) 2008年 09月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/07/25
- メディア: 雑誌
おお!早速実験されている。
SilentCはHTTP 1.1と言っているのでブラウザ側はKeep Aliveが有効とみなして、切断を待たずに同一ポート番号から再びリクエストを発行しているにも関わらず、SilentCは切断処理に入ってしまう。
つまり基本的にHTTP 1.0を名乗るべきではないのかと。
これはTCP/IPの動作ではなくhttpプロトコルの動作ですね。
3.番はよく判らないですね
by hamayan (2008-09-30 23:47)
どっちかと言えばブラウザ側が8秒掛かっている点が気になりますね。
本来FINは切断を意味するのではなく、「もうこちらからは送るデータは無いよ!」と言う意味です。
なのでFINを送信後も受信は可能です。
お互いにFINを送信する事で、双方で送るデータが無くなったのだから切断しようと言う流れです。と言っても私もそこまで実装を作り込んではいませんが。
ブラウザのFINの送信が遅れているのは、まだ何か送るつもりなのでしょうか?。
それに対してSilentCはタイムアウトしてしまっている様な感じですか。
by hamayan (2008-10-01 00:12)
やっぱり、HTTP/1.0と名乗る程度の実装だということですね。じゃあ、次はパッチを当ててみよう。
確かに、ブラウザが"FIN"を送るまでに8秒かかる理由は無いですね。GIFファイルの解析にそんなに時間がかかるとも思えない。ウィルスチェック?
ColdFireが送った#26と#29の"FIN"に対して、#27と#30で"ACK"が返ってきているのでColdFireは最後の"FIN"を待たずに、または時間切れでポートを閉じちゃったのだと思います。
ブラウザの"FIN"が遅れたのは、この後を考えて、HTMLにFORMタグを入れたことに理由があるのかも知れません。つまり、人間の反応が無いことを確認するために8秒間待っていたと。しかし、人間にとっては8秒間は短いな。それに、ブラウザがColdFireから到着した"FIN"を事実上、無視したことも解せない。
ColdFire「FINに対するACKが来たから、もうポート閉めちゃえ。」
ブラウザ「SUBMIT要求が無いからコネクションを切断しよう。」
ColdFire「FINが来たけど、このポートは無効だよね。棄てちゃオ。」
ブラウザ「FINを送ったのにACKが来ない。再送するか。」
ColdFire「FINが来たけど、このポートは無効だよね。棄てちゃオ。」
:
以下、続く
by noritan (2008-10-01 09:00)
htmlをコピーしてファイルにしてみました。
http://hamayan.ddo.jp/~hamayan/noritan.htm
うん、うん、これは楽しみだ。
オセロの前に3目並べはどうですか、名前をジョシュアとか付けて。
http://www.h2.dion.ne.jp/~mine/movie-0061.htm
by hamayan (2008-10-01 11:37)
300baudの音響カプラで電話をかけてくる、Dr.Falkenの息子さんですね。
by noritan (2008-10-01 14:03)