HTML文書にGIFをたくさん埋め込んでみた - Firefox の奥の手 [ColdFire V2]
付録基板の http サーバに Firefox で接続した時の問題は、同時に張るコネクション数が多すぎる為であるらしい事が分かってきました。 だったら、 Firefox に同時コネクション数を減らすように指示してやろう。
about:config というページの存在
Firefoxには、設定を変えるための"about:config"というページがあります。 アドレス欄に"about:config"と打ち込むと、この設定ページが開きます。 最近は、「動作保証外になります!」という警告が出てくるのね。 Firefoxに「動作保証」なんてあったんだっけ。
設定項目が山のように並んでいるので、必要な項目だけフィルタリングすることが出来ます。 ここでは、フィルタ欄に".http."と入力して必要な項目を出します。 それぞれの項目をダブル・クリックするか、右クリックでプルダウン・メニューを出して値を変更します。 付録基板のhttpサーバのご機嫌をとるために設定した項目は、以下の三つです。
設定名 | 値 | 備考 |
---|---|---|
network.http.max-connections-per-server | 3 | サーバあたりの最大コネクション数。 ColdFireは、最大三つしかコネクションを受け付けないらしい事が実験的にわかってきました。 Firefox 3.0.3のデフォルトは、なんと"15"になっていたので、付録基板がアップアップしていたのもうなずけます。 |
network.http.max-persistent-connections-per-server | 3 | サーバあたりの最大永続コネクション数。 どういうコネクションを意味するのか分かりませんが、デフォルトの"6"が大きすぎるのは明らかだと思います。 |
network.http.version | 1.0 | HTTPのバージョン。 デフォルトは、"1.1"でした。 これを"1.0"にすると、「HTTP/1.0にふさわしい振る舞い」をしてくれるようです。 |
パケット・モニタで解析
以上の設定を行ってから、パケット・モニタで解析しました。
#1 0.000000 192.168.1.2 192.168.1.10 TCP 1217 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #2 0.000364 192.168.1.10 192.168.1.2 TCP 80 > 1217 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #3 0.000438 192.168.1.2 192.168.1.10 TCP 1217 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #4 0.008139 192.168.1.2 192.168.1.10 HTTP GET /ShowGeaTemplate.htm HTTP/1.0 TCP 1217 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=420 #5 0.009089 192.168.1.10 192.168.1.2 TCP 80 > 1217 [ACK] Seq=1 Ack=421 Win=1454 Len=0 #6 0.012982 192.168.1.10 192.168.1.2 TCP [TCP segment of a reassembled PDU] TCP 80 > 1217 [PSH, ACK] Seq=1 Ack=421 Win=1454 Len=1408 #19 0.201169 192.168.1.2 192.168.1.10 TCP 1217 > 80 [ACK] Seq=421 Ack=1409 Win=16616 Len=0 #81 1.997214 192.168.1.10 192.168.1.2 TCP [TCP Retransmission] [TCP segment of a reassembled PDU] TCP [TCP Retransmission] 80 > 1217 [PSH, ACK] Seq=1 Ack=421 Win=1454 Len=1408 #82 1.997296 192.168.1.2 192.168.1.10 TCP [TCP Dup ACK 19#1] 1217 > 80 [ACK] Seq=421 Ack=1409 Win=16616 Len=0 #83 1.998617 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (text/html) TCP 80 > 1217 [PSH, ACK] Seq=1409 Ack=421 Win=1454 Len=388 #96 2.113152 192.168.1.2 192.168.1.10 TCP 1217 > 80 [ACK] Seq=421 Ack=1797 Win=16228 Len=0 #97 2.113542 192.168.1.10 192.168.1.2 TCP 80 > 1217 [FIN, ACK] Seq=1797 Ack=421 Win=1454 Len=0 #98 2.113645 192.168.1.2 192.168.1.10 TCP 1217 > 80 [ACK] Seq=421 Ack=1798 Win=16228 Len=0 #99 2.114382 192.168.1.2 192.168.1.10 TCP 1217 > 80 [FIN, ACK] Seq=421 Ack=1798 Win=16228 Len=0 #100 2.114713 192.168.1.10 192.168.1.2 TCP 80 > 1217 [ACK] Seq=1798 Ack=422 Win=1454 Len=0
第1コネクションは、ポート1217でHTML文書を要求します。 途中でブラウザの送った"ACK"(#19)を付録基板が取り損ねたため、#81で再送が発生していますが、2秒ちょっとでコネクションは完了します。
#7 0.054576 192.168.1.2 192.168.1.10 TCP 1220 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #8 0.054906 192.168.1.10 192.168.1.2 TCP 80 > 1220 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #9 0.054970 192.168.1.2 192.168.1.10 TCP 1220 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #10 0.055850 192.168.1.2 192.168.1.10 HTTP GET /Ke1.gif HTTP/1.0 TCP 1220 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=428 #11 0.056772 192.168.1.10 192.168.1.2 TCP 80 > 1220 [ACK] Seq=1 Ack=429 Win=1454 Len=0 #12 0.058537 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (GIF89a) TCP 80 > 1220 [PSH, ACK] Seq=1 Ack=429 Win=1454 Len=645 #20 0.201248 192.168.1.2 192.168.1.10 TCP 1220 > 80 [ACK] Seq=429 Ack=646 Win=16616 Len=0 #90 2.046141 192.168.1.10 192.168.1.2 HTTP [TCP Retransmission] HTTP/1.1 200 OK (GIF89a) TCP [TCP Retransmission] 80 > 1220 [PSH, ACK] Seq=1 Ack=429 Win=1454 Len=645 #91 2.046218 192.168.1.2 192.168.1.10 TCP [TCP Dup ACK 20#1] 1220 > 80 [ACK] Seq=429 Ack=646 Win=16616 Len=0 #92 2.046701 192.168.1.10 192.168.1.2 TCP 80 > 1220 [FIN, ACK] Seq=646 Ack=429 Win=1454 Len=0 #93 2.046806 192.168.1.2 192.168.1.10 TCP 1220 > 80 [ACK] Seq=429 Ack=647 Win=16616 Len=0 #94 2.047666 192.168.1.2 192.168.1.10 TCP 1220 > 80 [FIN, ACK] Seq=429 Ack=647 Win=16616 Len=0 #95 2.047997 192.168.1.10 192.168.1.2 TCP 80 > 1220 [ACK] Seq=647 Ack=430 Win=1454 Len=0
第2コネクションは、ポート1220でGIFファイル Ke1.gif を要求します。 このコネクションも途中でブラウザからの"ACK"を付録基板が取り損ねる場面がありますが、それでも2秒ちょっとでコネクションは終了します。
#13 0.062049 192.168.1.2 192.168.1.10 TCP 1221 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #14 0.062428 192.168.1.10 192.168.1.2 TCP 80 > 1221 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #15 0.062493 192.168.1.2 192.168.1.10 TCP 1221 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #16 0.069947 192.168.1.2 192.168.1.10 HTTP GET /Ry0.gif HTTP/1.0 TCP 1221 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=428 #17 0.070920 192.168.1.10 192.168.1.2 TCP 80 > 1221 [ACK] Seq=1 Ack=429 Win=1454 Len=0 #18 0.072850 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (GIF89a) TCP 80 > 1221 [PSH, ACK] Seq=1 Ack=429 Win=1454 Len=692 #21 0.201278 192.168.1.2 192.168.1.10 TCP 1221 > 80 [ACK] Seq=429 Ack=693 Win=16616 Len=0 #22 0.201702 192.168.1.10 192.168.1.2 TCP 80 > 1221 [FIN, ACK] Seq=693 Ack=429 Win=1454 Len=0 #23 0.201799 192.168.1.2 192.168.1.10 TCP 1221 > 80 [ACK] Seq=429 Ack=694 Win=16616 Len=0 #24 0.202858 192.168.1.2 192.168.1.10 TCP 1221 > 80 [FIN, ACK] Seq=429 Ack=694 Win=16616 Len=0 #25 0.203185 192.168.1.10 192.168.1.2 TCP 80 > 1221 [ACK] Seq=694 Ack=430 Win=1454 Len=0
第3コネクションは、ポート1221でGIFファイル Ry0.gif を要求します。 ブラウザは、GIFファイルを受け取ったら、次のファイルを要求せずにコネクションを終了させます。
#26 0.212440 192.168.1.2 192.168.1.10 TCP 1223 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #27 0.212818 192.168.1.10 192.168.1.2 TCP 80 > 1223 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #28 0.212904 192.168.1.2 192.168.1.10 TCP 1223 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #29 0.220324 192.168.1.2 192.168.1.10 HTTP GET /Kn1.gif HTTP/1.0 TCP 1223 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=428 #30 0.221324 192.168.1.10 192.168.1.2 TCP 80 > 1223 [ACK] Seq=1 Ack=429 Win=1454 Len=0 #31 0.223138 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (GIF89a) TCP 80 > 1223 [PSH, ACK] Seq=1 Ack=429 Win=1454 Len=648 #32 0.402372 192.168.1.2 192.168.1.10 TCP 1223 > 80 [ACK] Seq=429 Ack=649 Win=16616 Len=0 #33 0.402791 192.168.1.10 192.168.1.2 TCP 80 > 1223 [FIN, ACK] Seq=649 Ack=429 Win=1454 Len=0 #34 0.402881 192.168.1.2 192.168.1.10 TCP 1223 > 80 [ACK] Seq=429 Ack=650 Win=16616 Len=0 #35 0.404767 192.168.1.2 192.168.1.10 TCP 1223 > 80 [FIN, ACK] Seq=429 Ack=650 Win=16616 Len=0 #36 0.405098 192.168.1.10 192.168.1.2 TCP 80 > 1223 [ACK] Seq=650 Ack=430 Win=1454 Len=0
第4コネクションは、ポート1223でGIFファイル Kn1.gif を要求します。 このコネクションの処理中は、他のコネクションを受けつけず、終了まで一気に進みます。
#37 0.412711 192.168.1.2 192.168.1.10 TCP 1225 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #38 0.413096 192.168.1.10 192.168.1.2 TCP 80 > 1225 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #39 0.413160 192.168.1.2 192.168.1.10 TCP 1225 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #40 0.420408 192.168.1.2 192.168.1.10 HTTP GET /Gn1.gif HTTP/1.0 TCP 1225 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=428 #41 0.421475 192.168.1.10 192.168.1.2 TCP 80 > 1225 [ACK] Seq=1 Ack=429 Win=1454 Len=0 #42 0.423206 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (GIF89a) TCP 80 > 1225 [PSH, ACK] Seq=1 Ack=429 Win=1454 Len=662 #43 0.603541 192.168.1.2 192.168.1.10 TCP 1225 > 80 [ACK] Seq=429 Ack=663 Win=16616 Len=0 #44 0.604028 192.168.1.10 192.168.1.2 TCP 80 > 1225 [FIN, ACK] Seq=663 Ack=429 Win=1454 Len=0 #45 0.604128 192.168.1.2 192.168.1.10 TCP 1225 > 80 [ACK] Seq=429 Ack=664 Win=16616 Len=0 #46 0.605874 192.168.1.2 192.168.1.10 TCP 1225 > 80 [FIN, ACK] Seq=429 Ack=664 Win=16616 Len=0 #47 0.606196 192.168.1.10 192.168.1.2 TCP 80 > 1225 [ACK] Seq=664 Ack=430 Win=1454 Len=0
第5コネクションは、ポート1225でGIFファイル Gn1.gif を要求します。 このコネクションも、終了まで一気に進みます。
#48 0.613631 192.168.1.2 192.168.1.10 TCP 1227 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #49 0.614064 192.168.1.10 192.168.1.2 TCP 80 > 1227 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #50 0.614135 192.168.1.2 192.168.1.10 TCP 1227 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #51 0.621146 192.168.1.2 192.168.1.10 HTTP GET /Gk1.gif HTTP/1.0 TCP 1227 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=428 #52 0.622119 192.168.1.10 192.168.1.2 TCP 80 > 1227 [ACK] Seq=1 Ack=429 Win=1454 Len=0 #53 0.623955 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (GIF89a) TCP 80 > 1227 [PSH, ACK] Seq=1 Ack=429 Win=1454 Len=669 #54 0.804724 192.168.1.2 192.168.1.10 TCP 1227 > 80 [ACK] Seq=429 Ack=670 Win=16616 Len=0 #55 0.805140 192.168.1.10 192.168.1.2 TCP 80 > 1227 [FIN, ACK] Seq=670 Ack=429 Win=1454 Len=0 #56 0.805229 192.168.1.2 192.168.1.10 TCP 1227 > 80 [ACK] Seq=429 Ack=671 Win=16616 Len=0 #57 0.806464 192.168.1.2 192.168.1.10 TCP 1227 > 80 [FIN, ACK] Seq=429 Ack=671 Win=16616 Len=0 #58 0.806805 192.168.1.10 192.168.1.2 TCP 80 > 1227 [ACK] Seq=671 Ack=430 Win=1454 Len=0
第6コネクションは、ポート1227でGIFファイル Gk1.gif を要求します。 このコネクションも、終了まで一気に進みます。
#59 0.814831 192.168.1.2 192.168.1.10 TCP 1229 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #60 0.815293 192.168.1.10 192.168.1.2 TCP 80 > 1229 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #61 0.815372 192.168.1.2 192.168.1.10 TCP 1229 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #62 0.822975 192.168.1.2 192.168.1.10 HTTP GET /Fu1.gif HTTP/1.0 TCP 1229 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=428 #63 0.824038 192.168.1.10 192.168.1.2 TCP 80 > 1229 [ACK] Seq=1 Ack=429 Win=1454 Len=0 #64 0.825702 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (GIF89a) TCP 80 > 1229 [PSH, ACK] Seq=1 Ack=429 Win=1454 Len=607 #65 1.005801 192.168.1.2 192.168.1.10 TCP 1229 > 80 [ACK] Seq=429 Ack=608 Win=16616 Len=0 #66 1.006182 192.168.1.10 192.168.1.2 TCP 80 > 1229 [FIN, ACK] Seq=608 Ack=429 Win=1454 Len=0 #67 1.006258 192.168.1.2 192.168.1.10 TCP 1229 > 80 [ACK] Seq=429 Ack=609 Win=16616 Len=0 #68 1.008603 192.168.1.2 192.168.1.10 TCP 1229 > 80 [FIN, ACK] Seq=429 Ack=609 Win=16616 Len=0 #69 1.008937 192.168.1.10 192.168.1.2 TCP 80 > 1229 [ACK] Seq=609 Ack=430 Win=1454 Len=0
第7コネクションは、ポート1229でGIFファイル Fu1.gif を要求します。 このコネクションも、終了まで一気に進みます。
#70 1.017496 192.168.1.2 192.168.1.10 TCP 1231 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #71 1.017957 192.168.1.10 192.168.1.2 TCP 80 > 1231 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #72 1.018031 192.168.1.2 192.168.1.10 TCP 1231 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #73 1.025341 192.168.1.2 192.168.1.10 TCP 1231 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=428 HTTP GET /Fu0.gif HTTP/1.0 #74 1.026367 192.168.1.10 192.168.1.2 TCP 80 > 1231 [ACK] Seq=1 Ack=429 Win=1454 Len=0 #75 1.027997 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (GIF89a) TCP 80 > 1231 [PSH, ACK] Seq=1 Ack=429 Win=1454 Len=608 #76 1.208014 192.168.1.2 192.168.1.10 TCP 1231 > 80 [ACK] Seq=429 Ack=609 Win=16616 Len=0 #77 1.208507 192.168.1.10 192.168.1.2 TCP 80 > 1231 [FIN, ACK] Seq=609 Ack=429 Win=1454 Len=0 #78 1.208618 192.168.1.2 192.168.1.10 TCP 1231 > 80 [ACK] Seq=429 Ack=610 Win=16616 Len=0 #79 1.209386 192.168.1.2 192.168.1.10 TCP 1231 > 80 [FIN, ACK] Seq=429 Ack=610 Win=16616 Len=0 #80 1.209733 192.168.1.10 192.168.1.2 TCP 80 > 1231 [ACK] Seq=610 Ack=430 Win=1454 Len=0
第8コネクションは、ポート1231でGIFファイル Fu0.gif を要求します。 このコネクションも、終了まで一気に進みます。
#84 2.013543 192.168.1.2 192.168.1.10 TCP 1233 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #85 2.013956 192.168.1.10 192.168.1.2 TCP 80 > 1233 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #86 2.014029 192.168.1.2 192.168.1.10 TCP 1233 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #87 2.021767 192.168.1.2 192.168.1.10 HTTP GET /Gn0.gif HTTP/1.0 TCP 1233 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=428 #88 2.022813 192.168.1.10 192.168.1.2 TCP 80 > 1233 [ACK] Seq=1 Ack=429 Win=1454 Len=0 #89 2.024573 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (GIF89a) TCP 80 > 1233 [PSH, ACK] Seq=1 Ack=429 Win=1454 Len=673 #101 2.213885 192.168.1.2 192.168.1.10 TCP 1233 > 80 [ACK] Seq=429 Ack=674 Win=16616 Len=0 #102 2.214359 192.168.1.10 192.168.1.2 TCP 80 > 1233 [FIN, ACK] Seq=674 Ack=429 Win=1454 Len=0 #103 2.214474 192.168.1.2 192.168.1.10 TCP 1233 > 80 [ACK] Seq=429 Ack=675 Win=16616 Len=0 #104 2.215284 192.168.1.2 192.168.1.10 TCP 1233 > 80 [FIN, ACK] Seq=429 Ack=675 Win=16616 Len=0 #105 2.215613 192.168.1.10 192.168.1.2 TCP 80 > 1233 [ACK] Seq=675 Ack=430 Win=1454 Len=0
最後の第9コネクションは、ポート1233でGIFファイル Gn0.gif を要求します。 このコネクションと前後して、第1、第2コネクションの再送処理が割り込んでくるため、一気に進むわけではありませんでした。 それでも、コネクション終了まで0.2秒と順調に進んでいます。
通信のまとめ
以上のように二箇所の再送処理はありましたが、全てのコネクションが2秒あまりで順調に終了しています。 しかも、取り損なった"ACK"も残っていません。 Firefoxで付録基板のhttpサーバと接続するときには、これぐらいの設定を行えば、実用的な速度でWEBページを表示することが出来そうです。
参考文献
Interface (インターフェース) 2008年 09月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/07/25
- メディア: 雑誌
HTML文書にGIFをたくさん埋め込んでみた - Internet Explorerの場合 [ColdFire V2]
前回のHTML文書をInternet Explorerで表示させてみました。 なぜか、全ての画像が表示されました。 どうしてなんだろう。
パケット・モニタで解析
では、早速、パケット・モニタで解析します。
#1 0.000000 192.168.1.2 192.168.1.10 TCP 1211 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #2 0.000446 192.168.1.10 192.168.1.2 TCP 80 > 1211 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #3 0.000519 192.168.1.2 192.168.1.10 TCP 1211 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #4 0.007449 192.168.1.2 192.168.1.10 HTTP GET /ShowGeaTemplate.htm HTTP/1.1 TCP 1211 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=322 #5 0.008347 192.168.1.10 192.168.1.2 TCP 80 > 1211 [ACK] Seq=1 Ack=323 Win=1454 Len=0 #6 0.012150 192.168.1.10 192.168.1.2 TCP [TCP segment of a reassembled PDU] TCP 80 > 1211 [PSH, ACK] Seq=1 Ack=323 Win=1454 Len=1408 #31 0.115099 192.168.1.2 192.168.1.10 TCP 1211 > 80 [ACK] Seq=323 Ack=1409 Win=16616 Len=0 #32 0.116324 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (text/html) TCP 80 > 1211 [PSH, ACK] Seq=1409 Ack=323 Win=1454 Len=388 #36 0.123218 192.168.1.2 192.168.1.10 HTTP GET /Fu1.gif HTTP/1.1 TCP 1211 > 80 [PSH, ACK] Seq=323 Ack=1797 Win=16228 Len=360 #37 0.124085 192.168.1.10 192.168.1.2 TCP 80 > 1211 [ACK] Seq=1797 Ack=683 Win=1454 Len=0 #38 0.124155 192.168.1.10 192.168.1.2 TCP 80 > 1211 [FIN, ACK] Seq=1797 Ack=683 Win=1454 Len=0 #39 0.124216 192.168.1.2 192.168.1.10 TCP 1211 > 80 [ACK] Seq=683 Ack=1798 Win=16228 Len=0 #40 0.124554 192.168.1.2 192.168.1.10 TCP 1211 > 80 [FIN, ACK] Seq=683 Ack=1798 Win=16228 Len=0 #41 0.125001 192.168.1.10 192.168.1.2 TCP 80 > 1211 [ACK] Seq=1798 Ack=684 Win=1454 Len=0
第1コネクションは、ポート1211を使って、HTML文書を取り寄せます。 Firefoxの時と同じように、コネクションを使いまわしてGIFファイル Fu1.gif も取り寄せようとしますが、ColdFireに切断を要求されてしまいます。
#7 0.069593 192.168.1.2 192.168.1.10 TCP 1213 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #8 0.069987 192.168.1.10 192.168.1.2 TCP 80 > 1213 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #9 0.070058 192.168.1.2 192.168.1.10 TCP 1213 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #10 0.077090 192.168.1.2 192.168.1.10 HTTP GET /Ry0.gif HTTP/1.1 TCP 1213 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=360 #11 0.078104 192.168.1.10 192.168.1.2 TCP 80 > 1213 [ACK] Seq=1 Ack=361 Win=1454 Len=0 #12 0.079939 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (GIF89a) TCP 80 > 1213 [PSH, ACK] Seq=1 Ack=361 Win=1454 Len=692 #13 0.085455 192.168.1.2 192.168.1.10 HTTP GET /Ke1.gif HTTP/1.1 TCP 1213 > 80 [PSH, ACK] Seq=361 Ack=693 Win=16616 Len=360 #14 0.086437 192.168.1.10 192.168.1.2 TCP 80 > 1213 [ACK] Seq=693 Ack=721 Win=1454 Len=0 #15 0.086491 192.168.1.10 192.168.1.2 TCP 80 > 1213 [FIN, ACK] Seq=693 Ack=721 Win=1454 Len=0 #16 0.086549 192.168.1.2 192.168.1.10 TCP 1213 > 80 [ACK] Seq=721 Ack=694 Win=16616 Len=0 #17 0.087115 192.168.1.2 192.168.1.10 TCP 1213 > 80 [FIN, ACK] Seq=721 Ack=694 Win=16616 Len=0 #18 0.087449 192.168.1.10 192.168.1.2 TCP 80 > 1213 [ACK] Seq=694 Ack=722 Win=1454 Len=0
第2コネクションは、ポート1213を使って、GIFファイル Ry0.gif を取り寄せます。 Ke1.gif の要求が拒否されるのは今まで同様です。 Firefoxとの違いは、 Ry0.gif の取り寄せ中は他のコネクションが張られない事です。
#19 0.095134 192.168.1.2 192.168.1.10 TCP 1215 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #20 0.095512 192.168.1.10 192.168.1.2 TCP 80 > 1215 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #21 0.095573 192.168.1.2 192.168.1.10 TCP 1215 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #22 0.102395 192.168.1.2 192.168.1.10 HTTP GET /Ke1.gif HTTP/1.1 TCP 1215 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=360 #23 0.103341 192.168.1.10 192.168.1.2 TCP 80 > 1215 [ACK] Seq=1 Ack=361 Win=1454 Len=0 #24 0.105101 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (GIF89a) TCP 80 > 1215 [PSH, ACK] Seq=1 Ack=361 Win=1454 Len=645 #25 0.109966 192.168.1.2 192.168.1.10 TCP 1215 > 80 [PSH, ACK] Seq=361 Ack=646 Win=16616 Len=360 HTTP GET /Gn1.gif HTTP/1.1 #26 0.110864 192.168.1.10 192.168.1.2 TCP 80 > 1215 [ACK] Seq=646 Ack=721 Win=1454 Len=0 #27 0.110913 192.168.1.10 192.168.1.2 TCP 80 > 1215 [FIN, ACK] Seq=646 Ack=721 Win=1454 Len=0 #28 0.110970 192.168.1.2 192.168.1.10 TCP 1215 > 80 [ACK] Seq=721 Ack=647 Win=16616 Len=0 #29 0.111549 192.168.1.2 192.168.1.10 TCP 1215 > 80 [FIN, ACK] Seq=721 Ack=647 Win=16616 Len=0 #30 0.111896 192.168.1.10 192.168.1.2 TCP 80 > 1215 [ACK] Seq=647 Ack=722 Win=1454 Len=0
第3コネクションは、ポート1215を使って、GIFファイル Ke1.gif を取り寄せ、続く Gn1.gif の要求が拒否されます。 この間も他のコネクションは張られません。
#33 0.121191 192.168.1.2 192.168.1.10 TCP 1217 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #34 0.121561 192.168.1.10 192.168.1.2 TCP 80 > 1217 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #35 0.121629 192.168.1.2 192.168.1.10 TCP 1217 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #57 0.149583 192.168.1.2 192.168.1.10 HTTP GET /Gn1.gif HTTP/1.1 TCP 1217 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=360 #58 0.150471 192.168.1.10 192.168.1.2 TCP 80 > 1217 [ACK] Seq=1 Ack=361 Win=1454 Len=0 #59 0.152216 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (GIF89a) TCP 80 > 1217 [PSH, ACK] Seq=1 Ack=361 Win=1454 Len=662 #60 0.157238 192.168.1.2 192.168.1.10 HTTP GET /Fu0.gif HTTP/1.1 TCP 1217 > 80 [PSH, ACK] Seq=361 Ack=663 Win=16616 Len=360 #61 0.158110 192.168.1.10 192.168.1.2 TCP 80 > 1217 [ACK] Seq=663 Ack=721 Win=1454 Len=0 #62 0.158182 192.168.1.10 192.168.1.2 TCP 80 > 1217 [FIN, ACK] Seq=663 Ack=721 Win=1454 Len=0 #63 0.158245 192.168.1.2 192.168.1.10 TCP 1217 > 80 [ACK] Seq=721 Ack=664 Win=16616 Len=0 #64 0.160412 192.168.1.2 192.168.1.10 TCP 1217 > 80 [FIN, ACK] Seq=721 Ack=664 Win=16616 Len=0 #65 0.160772 192.168.1.10 192.168.1.2 TCP 80 > 1217 [ACK] Seq=664 Ack=722 Win=1454 Len=0
第4コネクションは、ポート1217を使って、GIFファイル Gn1.gif を取り寄せ、続く Fu0.gif の要求が拒否されます。
#42 0.126065 192.168.1.2 192.168.1.10 TCP 1219 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #43 0.126425 192.168.1.10 192.168.1.2 TCP 80 > 1219 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #44 0.126492 192.168.1.2 192.168.1.10 TCP 1219 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #45 0.128055 192.168.1.2 192.168.1.10 HTTP GET /Fu1.gif HTTP/1.1 TCP 1219 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=360 #46 0.128916 192.168.1.10 192.168.1.2 TCP 80 > 1219 [ACK] Seq=1 Ack=361 Win=1454 Len=0 #47 0.130562 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (GIF89a) TCP 80 > 1219 [PSH, ACK] Seq=1 Ack=361 Win=1454 Len=607 #48 0.143724 192.168.1.2 192.168.1.10 HTTP GET /Kn1.gif HTTP/1.1 TCP 1219 > 80 [PSH, ACK] Seq=361 Ack=608 Win=16616 Len=360 #49 0.144606 192.168.1.10 192.168.1.2 TCP 80 > 1219 [ACK] Seq=608 Ack=721 Win=1454 Len=0 #50 0.144767 192.168.1.10 192.168.1.2 TCP 80 > 1219 [FIN, ACK] Seq=608 Ack=721 Win=1454 Len=0 #51 0.144826 192.168.1.2 192.168.1.10 TCP 1219 > 80 [ACK] Seq=721 Ack=609 Win=16616 Len=0 #52 0.145190 192.168.1.2 192.168.1.10 TCP 1219 > 80 [FIN, ACK] Seq=721 Ack=609 Win=16616 Len=0 #53 0.145520 192.168.1.10 192.168.1.2 TCP 80 > 1219 [ACK] Seq=609 Ack=722 Win=1454 Len=0
第5コネクションは、第1コネクションが終了したころに始まり、ポート1219を使って、GIFファイル Fu1.gif を取り寄せ、続く Kn1.gif の要求が拒否されます。
#54 0.148990 192.168.1.2 192.168.1.10 TCP 1221 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #55 0.149357 192.168.1.10 192.168.1.2 TCP 80 > 1221 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #56 0.149418 192.168.1.2 192.168.1.10 TCP 1221 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #66 0.161187 192.168.1.2 192.168.1.10 HTTP GET /Kn1.gif HTTP/1.1 TCP 1221 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=360 #67 0.162054 192.168.1.10 192.168.1.2 TCP 80 > 1221 [ACK] Seq=1 Ack=361 Win=1454 Len=0 #68 0.163838 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (GIF89a) TCP 80 > 1221 [PSH, ACK] Seq=1 Ack=361 Win=1454 Len=648 #69 0.168871 192.168.1.2 192.168.1.10 HTTP GET /Gk1.gif HTTP/1.1 TCP 1221 > 80 [PSH, ACK] Seq=361 Ack=649 Win=16616 Len=360 #70 0.169841 192.168.1.10 192.168.1.2 TCP 80 > 1221 [ACK] Seq=649 Ack=721 Win=1454 Len=0 #71 0.169886 192.168.1.10 192.168.1.2 TCP 80 > 1221 [FIN, ACK] Seq=649 Ack=721 Win=1454 Len=0 #72 0.169948 192.168.1.2 192.168.1.10 TCP 1221 > 80 [ACK] Seq=721 Ack=650 Win=16616 Len=0 #73 0.170350 192.168.1.2 192.168.1.10 TCP 1221 > 80 [FIN, ACK] Seq=721 Ack=650 Win=16616 Len=0 #74 0.170688 192.168.1.10 192.168.1.2 TCP 80 > 1221 [ACK] Seq=650 Ack=722 Win=1454 Len=0
第6コネクションは、ポート1221を使って、GIFファイル Kn1.gif を取り寄せ、続く Gk1.gif の要求が拒否されます。
#75 0.174090 192.168.1.2 192.168.1.10 TCP 1224 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #76 0.174453 192.168.1.10 192.168.1.2 TCP 80 > 1224 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #77 0.174519 192.168.1.2 192.168.1.10 TCP 1224 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #78 0.175500 192.168.1.2 192.168.1.10 HTTP GET /Gk1.gif HTTP/1.1 TCP 1224 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=360 #80 0.176384 192.168.1.10 192.168.1.2 TCP 80 > 1224 [ACK] Seq=1 Ack=361 Win=1454 Len=0 #81 0.178184 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (GIF89a) TCP 80 > 1224 [PSH, ACK] Seq=1 Ack=361 Win=1454 Len=669 #82 0.183174 192.168.1.2 192.168.1.10 HTTP GET /Gn0.gif HTTP/1.1 TCP 1224 > 80 [PSH, ACK] Seq=361 Ack=670 Win=16616 Len=360 #83 0.184038 192.168.1.10 192.168.1.2 TCP 80 > 1224 [ACK] Seq=670 Ack=721 Win=1454 Len=0 #84 0.184109 192.168.1.10 192.168.1.2 TCP 80 > 1224 [FIN, ACK] Seq=670 Ack=721 Win=1454 Len=0 #85 0.184165 192.168.1.2 192.168.1.10 TCP 1224 > 80 [ACK] Seq=721 Ack=671 Win=16616 Len=0 #86 0.184478 192.168.1.2 192.168.1.10 TCP 1224 > 80 [FIN, ACK] Seq=721 Ack=671 Win=16616 Len=0 #87 0.184829 192.168.1.10 192.168.1.2 TCP 80 > 1224 [ACK] Seq=671 Ack=722 Win=1454 Len=0
第7コネクションは、ポート1224を使って、GIFファイル Gk1.gif を取り寄せ、続く Gn0.gif の要求が拒否されます。
#79 0.176139 192.168.1.2 192.168.1.10 TCP 1225 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #97 3.132799 192.168.1.2 192.168.1.10 TCP 1225 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #98 3.133263 192.168.1.10 192.168.1.2 TCP 80 > 1225 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #99 3.133371 192.168.1.2 192.168.1.10 TCP 1225 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #100 3.141256 192.168.1.2 192.168.1.10 HTTP GET /Fu0.gif HTTP/1.1 #100 3.141256 192.168.1.2 192.168.1.10 TCP 1225 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=360 #101 3.142211 192.168.1.10 192.168.1.2 TCP 80 > 1225 [ACK] Seq=1 Ack=361 Win=1454 Len=0 #102 3.143835 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (GIF89a) #102 3.143835 192.168.1.10 192.168.1.2 TCP 80 > 1225 [PSH, ACK] Seq=1 Ack=361 Win=1454 Len=608 #103 3.333871 192.168.1.2 192.168.1.10 TCP 1225 > 80 [ACK] Seq=361 Ack=609 Win=16616 Len=0 #104 3.334286 192.168.1.10 192.168.1.2 TCP 80 > 1225 [FIN, ACK] Seq=609 Ack=361 Win=1454 Len=0 #105 3.334356 192.168.1.2 192.168.1.10 TCP 1225 > 80 [ACK] Seq=361 Ack=610 Win=16616 Len=0 #106 8.143978 192.168.1.2 192.168.1.10 TCP 1225 > 80 [FIN, ACK] Seq=361 Ack=610 Win=16616 Len=0 #108 8.144406 192.168.1.10 192.168.1.2 TCP 80 > 1225 [ACK] Seq=610 Ack=362 Win=1454 Len=0
第8コネクションは、ポート1225を使って、GIFファイル Fu0.gif を取り寄せます。 このコネクションは、#79の"SYN"がColdFireに無視されたため、3秒後に#97で"SYN"を再送して開始します。 また、ブラウザからの"FIN"の送信(#106)も#105の"ACK"の5秒後と遅く到着しています。
#88 0.192857 192.168.1.2 192.168.1.10 TCP 1227 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #89 0.193236 192.168.1.10 192.168.1.2 TCP 80 > 1227 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #90 0.193306 192.168.1.2 192.168.1.10 TCP 1227 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #91 0.200221 192.168.1.2 192.168.1.10 HTTP GET /Gn0.gif HTTP/1.1 TCP 1227 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=360 #92 0.201089 192.168.1.10 192.168.1.2 TCP 80 > 1227 [ACK] Seq=1 Ack=361 Win=1454 Len=0 #93 0.202868 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (GIF89a) TCP 80 > 1227 [PSH, ACK] Seq=1 Ack=361 Win=1454 Len=673 #94 0.316363 192.168.1.2 192.168.1.10 TCP 1227 > 80 [ACK] Seq=361 Ack=674 Win=16616 Len=0 #95 0.316852 192.168.1.10 192.168.1.2 TCP 80 > 1227 [FIN, ACK] Seq=674 Ack=361 Win=1454 Len=0 #96 0.316953 192.168.1.2 192.168.1.10 TCP 1227 > 80 [ACK] Seq=361 Ack=675 Win=16616 Len=0 #107 8.143979 192.168.1.2 192.168.1.10 TCP 1227 > 80 [FIN, ACK] Seq=361 Ack=675 Win=16616 Len=0 #109 10.475631 192.168.1.2 192.168.1.10 TCP 1227 > 80 [FIN, ACK] Seq=361 Ack=675 Win=16616 Len=0 #110 15.303797 192.168.1.2 192.168.1.10 TCP 1227 > 80 [FIN, ACK] Seq=361 Ack=675 Win=16616 Len=0 #111 24.859544 192.168.1.2 192.168.1.10 TCP 1227 > 80 [FIN, ACK] Seq=361 Ack=675 Win=16616 Len=0 #112 44.071617 192.168.1.2 192.168.1.10 TCP 1227 > 80 [FIN, ACK] Seq=361 Ack=675 Win=16616 Len=0
最後の第9コネクションは、ポート1227を使って、GIFファイル Gn0.gif を取り寄せます。 このコネクションだけは、接続が終了しませんでした。 このため、ブラウザは"FIN"を打ち続けます。
通信のまとめ
通信の様子を図にしてみました。 詰まっているので判断しづらいのですが、同時に存在するコネクションの数が二つに制限されているように見えます。 どうやら、コネクションの数が少なければ、httpサーバとの通信はうまくいくようです。 あるいは、Internet Explorer にチューニングしてあるのだろうか。
参考文献
Interface (インターフェース) 2008年 09月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/07/25
- メディア: 雑誌
HTML文書にGIFをたくさん埋め込んでみた - Firefoxの場合 [ColdFire V2]
httpサーバの能力を探るため、前回はGIFファイルを二つ埋め込んだHTML文書を表示しました。 今日は、もっともっと沢山のGIFファイルを埋め込んでみます。
HTML文書は、これだ
HTML文書として用意したのは、これです。 表の中にGIFファイルを配置します。
<html><head> <meta http-equiv="Content-Type" content="text/html; charset=Shift-JIS" /> <title>ShowGea</title> <style> table.board {text-align:center;} table.board td {width:32px;height:40px;background:#FF0;} </style> </head><body> <h1 style="text-align:center;">ShowGea</h1> <form action="ShowGeaAction.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="13"/></tr> <tr> <th rowspan="11"/> <th>9</th><th>8</th><th>7</th><th>6</th> <th>5</th><th>4</th><th>3</th><th>2</th><th>1</th> <th rowspan="11"/><th/><th rowspan="11"/> </tr> <tr><th colspan="9"/><th/></tr> <tr> <td/><td/><td/><td/><td/><td/> <td><img src="Ry0.gif"/></td> <td><img src="Ke1.gif"/></td> <td/> <th>一</th></tr> <tr> <td/><td/><td/><td/><td/> <td><img src="Kn1.gif"/></td> <td><img src="Kn1.gif"/></td> <td/><td/> <th>二</th></tr> <tr> <td/><td/><td/><td/><td/> <td><img src="Gn1.gif"/></td> <td><img src="Gk1.gif"/></td> <td><img src="Fu1.gif"/></td> <td/> <th>三</th></tr> <tr> <td/><td/><td/><td/><td/> <td><img src="Fu1.gif"/></td> <td><img src="Fu1.gif"/></td> <td/><td/> <th>四</th></tr> <tr> <td/><td/><td/><td/><td/><td/><td/> <td><img src="Fu0.gif"/></td> <td/> <th>五</th></tr> <tr> <td/><td/><td/><td/><td/><td/><td/><td/><td/> <th>六</th></tr> <tr> <td/><td/><td/><td/><td/><td/><td/><td/><td/> <th>七</th></tr> <tr> <td/><td/><td/><td/><td/><td/><td/><td/><td/> <th>八</th></tr> <tr> <td/><td/><td/><td/><td/><td/><td/><td/><td/> <th>九</th></tr> <tr><th colspan="13"/></tr> </table> </td> <td valign="bottom"> <img src="Gn0.gif"/> </td> </form> </body></html>
GIFファイルは、これだ
GIFファイルは、8種類、用意しました。
表示できたかな?
ブラウザで表示させましたが、後手の「歩」と先手の「銀」が表示されませんでした。 しかも、ここまで表示するのに60秒以上の時間を要しています。
表示されない画像は、その時々により変わります。 何度か試しましたが、全部の画像が表示されることはありませんでした。
パケット・モニタで通信状況を観測する
それでは、どんな通信が飛んでいるのかをパケット・モニタで確認します。 今回は、大量のパケットが飛んでいたので、ポート番号ごとにまとめました。
#1 0.000000 192.168.1.2 192.168.1.10 TCP 1147 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #2 0.000363 192.168.1.10 192.168.1.2 TCP 80 > 1147 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #3 0.000442 192.168.1.2 192.168.1.10 TCP 1147 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #4 0.009277 192.168.1.2 192.168.1.10 HTTP GET /ShowGeaTemplate.htm HTTP/1.1 TCP 1147 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=445 #5 0.010282 192.168.1.10 192.168.1.2 TCP 80 > 1147 [ACK] Seq=1 Ack=446 Win=1454 Len=0 #6 0.014162 192.168.1.10 192.168.1.2 TCP [TCP segment of a reassembled PDU] TCP 80 > 1147 [PSH, ACK] Seq=1 Ack=446 Win=1454 Len=1408 #46 0.127027 192.168.1.2 192.168.1.10 TCP 1147 > 80 [ACK] Seq=446 Ack=1409 Win=16616 Len=0 #47 0.128351 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (text/html) TCP 80 > 1147 [PSH, ACK] Seq=1409 Ack=446 Win=1454 Len=388 #54 0.328246 192.168.1.2 192.168.1.10 TCP 1147 > 80 [ACK] Seq=446 Ack=1797 Win=16228 Len=0 #55 0.328687 192.168.1.10 192.168.1.2 TCP 80 > 1147 [FIN, ACK] Seq=1797 Ack=446 Win=1454 Len=0 #56 0.328789 192.168.1.2 192.168.1.10 TCP 1147 > 80 [ACK] Seq=446 Ack=1798 Win=16228 Len=0 #64 2.066340 192.168.1.2 192.168.1.10 TCP 1147 > 80 [FIN, ACK] Seq=446 Ack=1798 Win=16228 Len=0 #66 2.066761 192.168.1.10 192.168.1.2 TCP 80 > 1147 [ACK] Seq=1798 Ack=447 Win=1454 Len=0
最初は、HTML文書の要求と受け取りです。 HTML文書が長かったので、#6と#47の二つのパケットに分割されたようです。
#7 0.046040 192.168.1.2 192.168.1.10 TCP 1151 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #8 0.046430 192.168.1.10 192.168.1.2 TCP 80 > 1151 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #9 0.046498 192.168.1.2 192.168.1.10 TCP 1151 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #10 0.048723 192.168.1.2 192.168.1.10 HTTP GET /Ke1.gif HTTP/1.1 TCP 1151 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=453 #11 0.049733 192.168.1.10 192.168.1.2 TCP 80 > 1151 [ACK] Seq=1 Ack=454 Win=1454 Len=0 #16 0.051729 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (GIF89a) TCP 80 > 1151 [PSH, ACK] Seq=1 Ack=454 Win=1454 Len=645 #21 0.057742 192.168.1.2 192.168.1.10 HTTP GET /Fu1.gif HTTP/1.1 TCP 1151 > 80 [PSH, ACK] Seq=454 Ack=646 Win=16616 Len=453 #22 0.058786 192.168.1.10 192.168.1.2 TCP 80 > 1151 [ACK] Seq=646 Ack=907 Win=1454 Len=0 #23 0.058922 192.168.1.10 192.168.1.2 TCP 80 > 1151 [FIN, ACK] Seq=646 Ack=907 Win=1454 Len=0 #24 0.058981 192.168.1.2 192.168.1.10 TCP 1151 > 80 [ACK] Seq=907 Ack=647 Win=16616 Len=0 #25 0.060721 192.168.1.2 192.168.1.10 TCP 1151 > 80 [FIN, ACK] Seq=907 Ack=647 Win=16616 Len=0 #26 0.061056 192.168.1.10 192.168.1.2 TCP 80 > 1151 [ACK] Seq=647 Ack=908 Win=1454 Len=0
HTML文書の一つ目のパケットが届いた頃、二つ目のコネクションとして、#7で最初のGIFファイル Ke1.gif の要求が始まります。 #15でGIFファイルが届きますが、ブラウザは同じポートで別のGIFファイル Fu1.gif を要求しようとします。 この要求は、ColdFireによる#23のコネクション切断要求で拒否されます。
#12 0.050124 192.168.1.2 192.168.1.10 TCP 1153 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #14 0.050717 192.168.1.10 192.168.1.2 TCP 80 > 1153 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #15 0.050804 192.168.1.2 192.168.1.10 TCP 1153 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #17 0.052502 192.168.1.2 192.168.1.10 HTTP GET /Kn1.gif HTTP/1.1 TCP 1153 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=453 #18 0.053565 192.168.1.10 192.168.1.2 TCP 80 > 1153 [ACK] Seq=1 Ack=454 Win=1454 Len=0 #20 0.055524 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (GIF89a) TCP 80 > 1153 [PSH, ACK] Seq=1 Ack=454 Win=1454 Len=648 #27 0.062373 192.168.1.2 192.168.1.10 HTTP GET /Fu1.gif HTTP/1.1 TCP 1153 > 80 [PSH, ACK] Seq=454 Ack=649 Win=16616 Len=453 #29 0.063429 192.168.1.10 192.168.1.2 TCP 80 > 1153 [ACK] Seq=649 Ack=907 Win=1454 Len=0 #30 0.063528 192.168.1.10 192.168.1.2 TCP 80 > 1153 [FIN, ACK] Seq=649 Ack=907 Win=1454 Len=0 #31 0.063586 192.168.1.2 192.168.1.10 TCP 1153 > 80 [ACK] Seq=907 Ack=650 Win=16616 Len=0 #34 0.064338 192.168.1.2 192.168.1.10 TCP 1153 > 80 [FIN, ACK] Seq=907 Ack=650 Win=16616 Len=0 #35 0.064678 192.168.1.10 192.168.1.2 TCP 80 > 1153 [ACK] Seq=650 Ack=908 Win=1454 Len=0
Ke1.gif の要求とほぼ同時に三つ目のコネクションで Kn1.gif の要求が始まります。 ブラウザは、このポートでも連続して Fu1.gif を要求しようとしますが、ColdFireに拒否されます。
#13 0.050700 192.168.1.2 192.168.1.10 TCP 1154 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #79 3.044079 192.168.1.2 192.168.1.10 TCP 1154 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #101 8.979695 192.168.1.2 192.168.1.10 TCP 1154 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #102 8.980156 192.168.1.10 192.168.1.2 TCP 80 > 1154 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #103 8.980279 192.168.1.2 192.168.1.10 TCP 1154 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #104 8.988016 192.168.1.2 192.168.1.10 HTTP GET /Gn1.gif HTTP/1.1 TCP 1154 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=453 #105 8.989119 192.168.1.10 192.168.1.2 TCP 80 > 1154 [ACK] Seq=1 Ack=454 Win=1454 Len=0 #106 8.990853 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (GIF89a) TCP 80 > 1154 [PSH, ACK] Seq=1 Ack=454 Win=1454 Len=662 #107 9.180864 192.168.1.2 192.168.1.10 TCP 1154 > 80 [ACK] Seq=454 Ack=663 Win=16616 Len=0 #108 9.181377 192.168.1.10 192.168.1.2 TCP 80 > 1154 [FIN, ACK] Seq=663 Ack=454 Win=1454 Len=0 #109 9.181489 192.168.1.2 192.168.1.10 TCP 1154 > 80 [ACK] Seq=454 Ack=664 Win=16616 Len=0 #110 17.664269 192.168.1.2 192.168.1.10 TCP 1154 > 80 [FIN, ACK] Seq=454 Ack=664 Win=16616 Len=0 #114 20.044274 192.168.1.2 192.168.1.10 TCP 1154 > 80 [FIN, ACK] Seq=454 Ack=664 Win=16616 Len=0 #117 24.872450 192.168.1.2 192.168.1.10 TCP 1154 > 80 [FIN, ACK] Seq=454 Ack=664 Win=16616 Len=0 #120 34.428232 192.168.1.2 192.168.1.10 TCP 1154 > 80 [FIN, ACK] Seq=454 Ack=664 Win=16616 Len=0
さらに、ブラウザは、#13で四つ目のコネクションを張ろうとしますが、ColdFireに取り合ってくれません。 #79で再送、#101で再々送して、やっとコネクションを張ることが出来ました。 このポートでは、 Gn1.gif を受け取ります。 ブラウザは、コネクションの終了を宣言しますが、ColdFireが最後の"ACK"を返してくれないので、"FIN"を繰り返し送信します。
#19 0.054023 192.168.1.2 192.168.1.10 TCP 1156 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #80 3.044117 192.168.1.2 192.168.1.10 TCP 1156 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #83 3.044657 192.168.1.10 192.168.1.2 TCP 80 > 1156 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #84 3.044715 192.168.1.2 192.168.1.10 TCP 1156 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #85 3.052257 192.168.1.2 192.168.1.10 HTTP GET /Gk1.gif HTTP/1.1 TCP 1156 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=453 #86 3.053334 192.168.1.10 192.168.1.2 TCP 80 > 1156 [ACK] Seq=1 Ack=454 Win=1454 Len=0 #87 3.055214 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (GIF89a) TCP 80 > 1156 [PSH, ACK] Seq=1 Ack=454 Win=1454 Len=669 #92 3.245282 192.168.1.2 192.168.1.10 TCP 1156 > 80 [ACK] Seq=454 Ack=670 Win=16616 Len=0 #95 5.045620 192.168.1.10 192.168.1.2 HTTP [TCP Retransmission] HTTP/1.1 200 OK (GIF89a) TCP [TCP Retransmission] 80 > 1156 [PSH, ACK] Seq=1 Ack=454 Win=1454 Len=669 #96 5.045686 192.168.1.2 192.168.1.10 TCP [TCP Dup ACK 92#1] 1156 > 80 [ACK] Seq=454 Ack=670 Win=16616 Len=0 #99 5.046065 192.168.1.10 192.168.1.2 TCP 80 > 1156 [FIN, ACK] Seq=670 Ack=454 Win=1454 Len=0 #100 5.046117 192.168.1.2 192.168.1.10 TCP 1156 > 80 [ACK] Seq=454 Ack=671 Win=16616 Len=0 #112 17.664570 192.168.1.2 192.168.1.10 TCP 1156 > 80 [FIN, ACK] Seq=454 Ack=671 Win=16616 Len=0 #115 20.044305 192.168.1.2 192.168.1.10 TCP 1156 > 80 [FIN, ACK] Seq=454 Ack=671 Win=16616 Len=0 #118 24.872481 192.168.1.2 192.168.1.10 TCP 1156 > 80 [FIN, ACK] Seq=454 Ack=671 Win=16616 Len=0 #121 34.428264 192.168.1.2 192.168.1.10 TCP 1156 > 80 [FIN, ACK] Seq=454 Ack=671 Win=16616 Len=0 #125 53.640459 192.168.1.2 192.168.1.10 TCP 1156 > 80 [FIN, ACK] Seq=454 Ack=671 Win=16616 Len=0 #128 92.064599 192.168.1.2 192.168.1.10 TCP 1156 > 80 [FIN, ACK] Seq=454 Ack=671 Win=16616 Len=0
ブラウザは、#19で五つ目のコネクションを張ろうとしますが、これもなかなか取り合ってもらえません。 ブラウザが#85で Gn1.gif を要求し、ColdFireは、#87でGIFファイルを送ります。 これに対してブラウザが送った#92の"ACK"をどうやらColdFireが取り損ねたらしく、#95でGIFファイルが再送されています。 ここでも、ブラウザは、コネクションの終了を宣言しますが、ColdFireが最後の"ACK"を返してくれないので、"FIN"を繰り返し送信しています。
#28 0.062749 192.168.1.2 192.168.1.10 TCP 1158 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #32 0.063679 192.168.1.10 192.168.1.2 TCP 80 > 1158 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #33 0.063743 192.168.1.2 192.168.1.10 TCP 1158 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #36 0.067982 192.168.1.2 192.168.1.10 HTTP GET /Fu0.gif HTTP/1.1 TCP 1158 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=453 #37 0.069018 192.168.1.10 192.168.1.2 TCP 80 > 1158 [ACK] Seq=1 Ack=454 Win=1454 Len=0 #38 0.070685 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (GIF89a) TCP 80 > 1158 [PSH, ACK] Seq=1 Ack=454 Win=1454 Len=608 #48 0.133867 192.168.1.2 192.168.1.10 HTTP GET /Gn0.gif HTTP/1.1 TCP 1158 > 80 [PSH, ACK] Seq=454 Ack=609 Win=16616 Len=453 #49 0.134905 192.168.1.10 192.168.1.2 TCP 80 > 1158 [ACK] Seq=609 Ack=907 Win=1454 Len=0 #50 0.135040 192.168.1.10 192.168.1.2 TCP 80 > 1158 [FIN, ACK] Seq=609 Ack=907 Win=1454 Len=0 #51 0.135101 192.168.1.2 192.168.1.10 TCP 1158 > 80 [ACK] Seq=907 Ack=610 Win=16616 Len=0 #53 0.136891 192.168.1.2 192.168.1.10 TCP 1158 > 80 [FIN, ACK] Seq=907 Ack=610 Win=16616 Len=0 #57 2.039185 192.168.1.2 192.168.1.10 TCP 1158 > 80 [FIN, ACK] Seq=907 Ack=610 Win=16616 Len=0 #58 2.039637 192.168.1.10 192.168.1.2 TCP 80 > 1158 [ACK] Seq=610 Ack=908 Win=1454 Len=0
六つ目のコネクションは、二つ目のコネクションが#26で終了した頃に要求が始まります。 このため、すぐにコネクションが張られます。 このコネクションでもブラウザから#48で連続した要求が届きますが、ColdFireは、コネクションを終了してしまいます。
#39 0.071854 192.168.1.2 192.168.1.10 TCP 1160 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #40 0.072268 192.168.1.10 192.168.1.2 TCP 80 > 1160 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #41 0.072336 192.168.1.2 192.168.1.10 TCP 1160 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #43 0.080597 192.168.1.2 192.168.1.10 HTTP GET /Ry0.gif HTTP/1.1 TCP 1160 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=453 #44 0.081715 192.168.1.10 192.168.1.2 TCP 80 > 1160 [ACK] Seq=1 Ack=454 Win=1454 Len=0 #45 0.083605 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (GIF89a) TCP 80 > 1160 [PSH, ACK] Seq=1 Ack=454 Win=1454 Len=692 #52 0.136722 192.168.1.2 192.168.1.10 HTTP GET /Gn0.gif HTTP/1.1 TCP 1160 > 80 [PSH, ACK] Seq=454 Ack=693 Win=16616 Len=453 #59 2.064560 192.168.1.10 192.168.1.2 HTTP [TCP Retransmission] HTTP/1.1 200 OK (GIF89a) TCP [TCP Retransmission] 80 > 1160 [PSH, ACK] Seq=1 Ack=454 Win=1454 Len=692 #60 2.064641 192.168.1.2 192.168.1.10 TCP [TCP Dup ACK 52#1] 1160 > 80 [ACK] Seq=907 Ack=693 Win=16616 Len=0 #61 2.065105 192.168.1.10 192.168.1.2 TCP 80 > 1160 [FIN, ACK] Seq=693 Ack=454 Win=1454 Len=0 #62 2.065201 192.168.1.2 192.168.1.10 TCP 1160 > 80 [ACK] Seq=907 Ack=694 Win=16616 Len=0 #63 2.066272 192.168.1.2 192.168.1.10 TCP 1160 > 80 [FIN, ACK] Seq=907 Ack=694 Win=16616 Len=0 #65 2.066600 192.168.1.10 192.168.1.2 TCP 80 > 1160 [ACK] Seq=694 Ack=908 Win=1454 Len=0
七つ目のコネクションは、三つ目のコネクションが#35で終了した頃に要求が始まります。 このため、すぐにコネクションが張られます。 このコネクションでもブラウザから#52で連続した要求が届きますが、ColdFireは、この要求自体を受け取り損ねたらしく、#59でGIFファイルを再送します。 その後、ブラウザからは#60でGIFファイルの要求ではなく受信確認だけが届き、コネクション終了のシーケンスに移ります。
#42 0.074501 192.168.1.2 192.168.1.10 TCP 1161 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #78 3.044077 192.168.1.2 192.168.1.10 TCP 1161 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #81 3.044532 192.168.1.10 192.168.1.2 TCP 80 > 1161 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #82 3.044643 192.168.1.2 192.168.1.10 TCP 1161 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #88 3.059866 192.168.1.2 192.168.1.10 HTTP GET /Fu1.gif HTTP/1.1 TCP 1161 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=453 #89 3.060889 192.168.1.10 192.168.1.2 TCP 80 > 1161 [ACK] Seq=1 Ack=454 Win=1454 Len=0 #90 3.062576 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (GIF89a) TCP 80 > 1161 [PSH, ACK] Seq=1 Ack=454 Win=1454 Len=607 #91 3.245280 192.168.1.2 192.168.1.10 TCP 1161 > 80 [ACK] Seq=454 Ack=608 Win=16616 Len=0 #93 5.044902 192.168.1.10 192.168.1.2 HTTP [TCP Retransmission] HTTP/1.1 200 OK (GIF89a) TCP [TCP Retransmission] 80 > 1161 [PSH, ACK] Seq=1 Ack=454 Win=1454 Len=607 #94 5.044997 192.168.1.2 192.168.1.10 TCP [TCP Dup ACK 91#1] 1161 > 80 [ACK] Seq=454 Ack=608 Win=16616 Len=0 #97 5.045957 192.168.1.10 192.168.1.2 TCP 80 > 1161 [FIN, ACK] Seq=608 Ack=454 Win=1454 Len=0 #98 5.046053 192.168.1.2 192.168.1.10 TCP 1161 > 80 [ACK] Seq=454 Ack=609 Win=16616 Len=0 #111 17.664388 192.168.1.2 192.168.1.10 TCP 1161 > 80 [FIN, ACK] Seq=454 Ack=609 Win=16616 Len=0 #113 20.043312 192.168.1.2 192.168.1.10 TCP 1161 > 80 [FIN, ACK] Seq=454 Ack=609 Win=16616 Len=0 #116 24.871494 192.168.1.2 192.168.1.10 TCP 1161 > 80 [FIN, ACK] Seq=454 Ack=609 Win=16616 Len=0 #119 34.427265 192.168.1.2 192.168.1.10 TCP 1161 > 80 [FIN, ACK] Seq=454 Ack=609 Win=16616 Len=0 #122 53.639394 192.168.1.2 192.168.1.10 TCP 1161 > 80 [FIN, ACK] Seq=454 Ack=609 Win=16616 Len=0 #126 92.063594 192.168.1.2 192.168.1.10 TCP 1161 > 80 [FIN, ACK] Seq=454 Ack=609 Win=16616 Len=0
八つ目のコネクションは、しばらく取り合ってもらえません。 コネクションが張られるのは、3秒後です。 このコネクションでも、ColdFireが"ACK"を取り損ねていて、GIFファイルを再送しています。 その後は、ブラウザが切断宣言を繰り返し送信します。
#67 2.075707 192.168.1.2 192.168.1.10 TCP 1163 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #68 2.076085 192.168.1.10 192.168.1.2 TCP 80 > 1163 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #69 2.076149 192.168.1.2 192.168.1.10 TCP 1163 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #70 2.083182 192.168.1.2 192.168.1.10 HTTP GET /Gn0.gif HTTP/1.1 TCP 1163 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=453 #71 2.084216 192.168.1.10 192.168.1.2 TCP 80 > 1163 [ACK] Seq=1 Ack=454 Win=1454 Len=0 #72 2.086017 192.168.1.10 192.168.1.2 HTTP HTTP/1.1 200 OK (GIF89a) TCP 80 > 1163 [PSH, ACK] Seq=1 Ack=454 Win=1454 Len=673 #73 2.239398 192.168.1.2 192.168.1.10 TCP 1163 > 80 [ACK] Seq=454 Ack=674 Win=16616 Len=0 #74 2.239879 192.168.1.10 192.168.1.2 TCP 80 > 1163 [FIN, ACK] Seq=674 Ack=454 Win=1454 Len=0 #75 2.239981 192.168.1.2 192.168.1.10 TCP 1163 > 80 [ACK] Seq=454 Ack=675 Win=16616 Len=0 #76 2.662937 192.168.1.2 192.168.1.10 TCP 1163 > 80 [FIN, ACK] Seq=454 Ack=675 Win=16616 Len=0 #77 2.663310 192.168.1.10 192.168.1.2 TCP 80 > 1163 [ACK] Seq=675 Ack=455 Win=1454 Len=0
九つ目の最後のコネクションは、他のコネクションが終了した頃に始まったため、すんなりと通信が行われます。
通信のまとめ
それぞれのコネクションをColdFireがブラウザの"SYN"に反応した順に表にしてみました。
ポート | ファイル | コネクション |
---|---|---|
1147 | HTML | #2 - #66 |
1151 | Ke1.gif | #8 - #26 |
1153 | Kn1.gif | #14 - #35 |
1158 | Fu0.gif | #32 - #58 |
1160 | Ry0.gif | #40 - #65 |
1163 | Gn0.gif | #68 - #77 |
1161 | Fu1.gif | #78 - |
1156 | Gk1.gif | #80 - |
1154 | Gn1.gif | #79 - |
図も描いてみました。 緑色の部分が実際にデータを送受信した部分です。 ブラウザの再送間隔が長いために全体の通信時間が長くなってしまったものと思われます。
この表から、httpサーバが同時に張ることができるのは、最大三つのコネクションらしいことがわかります。 また、最後の三つのコネクションについては、コネクションが確実に終了していません。 どのGIFファイルもデータそのものは送られてきているのですが、コネクションの終了が確実ではないために破損したイメージとして表示されるものと思われます。
次回はIEでの通信をパケット・モニタにかけます。
参考文献
Interface (インターフェース) 2008年 09月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/07/25
- メディア: 雑誌
付録基板のhttpサーバをダウングレードしてみた [ColdFire V2]
SilentCにパッチをあてて、httpサーバをダウングレードしてみました。 これも、"masato"さんの尊い人柱レポートのおかげです。
httpサーバのダウングレード
この作業は、SilentCにパッチをあてることになるので、付録基板がEzPORTによるリカバリを必要とするぐらいのダメージを受ける可能性があります。 このため、今まで使ってきた「青号」ではなく「橙号」を出してきました。 皆さんが追試されるときにも十分に注意してください。
ダウン・グレードといっても、大したことはしていません。 httpサーバが返してくる"HTTP/1.1 200 OK"の文字列を"HTTP/1.0 200 OK"に変更するだけです。 この文字列は、以下の場所にあります。
000116b8 74 73 3f 00 46 75 6c 6c ts?.Full 000116c0 3f 00 48 54 54 50 2f 31 ?.HTTP/1 000116c8 2e 31 20 32 30 30 20 4f .1 200 O 000116d0 4b 0d 0a 43 6f 6e 74 65 K..Conte
これを書き換えるためにドキュメントには書かれていない"NvmWrite"という関数を使います。 使用したプログラムは、以下のとおりです。
main(){ long *patch=MemoryAlloc(16); long *target=0x116c8; do { BufCopy(patch,target,4); if (*patch!=0x2e312032) { PrStr("Invalid Program\r\n"); break; } *patch=0x2e302032; NvmWrite(target+0xFFF00000, patch, 4); } while(0); MemoryFree(patch); }
"NvmWrite"という関数は、FLASHへの書き込みを行うプログラムをRAMに展開して、実行します。 この間、FLASHは、アクセス不能になります。 そのため、書き込みに必要な情報は、すべてRAMに配置しておく必要があります。 このプログラムでも該当アドレスの内容を"MemoryAlloc"関数で確保したヒープ領域に配置して、書き込むべきデータのバッファとして使用しています。
プログラムを実行した結果が、これです。
000116b8 74 73 3f 00 46 75 6c 6c ts?.Full 000116c0 3f 00 48 54 54 50 2f 31 ?.HTTP/1 000116c8 2e 30 20 32 30 30 20 4f .0 200 O 000116d0 4b 0d 0a 43 6f 6e 74 65 K..Conte
この方法で、自由自在にパッチが当てられそうなのですが、適用範囲は限定されています。 今回は、0x31というデータを0x30というデータに書き換える「あるビットを1から0に変更するパッチ」だったので、簡単に出来ました。 もち、逆に「0から1に変更する」のだったら、FLASHを一旦消去して、書き換える必要があるので、こんなに簡単にはいきません。
また、このパッチは、該当箇所を余分にプログラムしてしまうことになるので、深く書き込みすぎてしまう可能性があります。 これは、「deep program」と呼ばれる状態で、セルが劣化したり、消去できなくなったりする可能性があります。 このFLASHモジュールの書き込みアルゴリズムがどうなっているのか、明確ではありませんが、あくまでも「消去してから書き込み」というのが正式な手順です。
パケット・モニタで確認
パッチをあてたところで、パケット・モニタで通信状態を確認してみます。
#1 0.000000 192.168.1.2 192.168.1.103 TCP 1517 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #2 0.000394 192.168.1.103 192.168.1.2 TCP 80 > 1517 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #3 0.000484 192.168.1.2 192.168.1.103 TCP 1517 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0
おなじみ3ウェイ・ハンドシェイクです。
#4 0.008741 192.168.1.2 192.168.1.103 HTTP GET /RiverSeaTemplate.htm HTTP/1.1 TCP 1517 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=430 #5 0.009719 192.168.1.103 192.168.1.2 TCP 80 > 1517 [ACK] Seq=1 Ack=431 Win=1454 Len=0 #6 0.013506 192.168.1.103 192.168.1.2 HTTP HTTP/1.0 200 OK (text/html) TCP 80 > 1517 [PSH, ACK] Seq=1 Ack=431 Win=1454 Len=1377
最初は、HTML文書の要求から。 ColdFireからの返答が"HTTP/1.0 200 OK"になっているのが確認できます。
#7 0.054387 192.168.1.2 192.168.1.103 HTTP GET /W.gif HTTP/1.1 TCP 1517 > 80 [PSH, ACK] Seq=431 Ack=1378 Win=16616 Len=437 #8 0.055376 192.168.1.103 192.168.1.2 TCP 80 > 1517 [ACK] Seq=1378 Ack=868 Win=1454 Len=0 #9 0.055416 192.168.1.103 192.168.1.2 TCP 80 > 1517 [FIN, ACK] Seq=1378 Ack=868 Win=1454 Len=0 #10 0.055472 192.168.1.2 192.168.1.103 TCP 1517 > 80 [ACK] Seq=868 Ack=1379 Win=16616 Len=0 #11 0.056353 192.168.1.2 192.168.1.103 TCP 1517 > 80 [FIN, ACK] Seq=868 Ack=1379 Win=16616 Len=0 #12 0.056673 192.168.1.103 192.168.1.2 TCP 80 > 1517 [ACK] Seq=1379 Ack=869 Win=1454 Len=0
ところが、ブラウザは、同じポートを使い#7でGIFファイル W.gif を要求してきます。 ColdFireは、#7に対する応答として#8を返しますが、同時に#9でコネクションの終了を宣言します。 この部分は、HTTP/1.1だった時と同じです。 ブラウザが、HTTP/1.0を認識していないのか?
#13 0.057777 192.168.1.2 192.168.1.103 TCP 1520 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #14 0.058129 192.168.1.103 192.168.1.2 TCP 80 > 1520 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #15 0.058201 192.168.1.2 192.168.1.103 TCP 1520 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #16 0.059826 192.168.1.2 192.168.1.103 HTTP GET /B.gif HTTP/1.1 TCP 1520 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=437 #17 0.060798 192.168.1.103 192.168.1.2 TCP 80 > 1520 [ACK] Seq=1 Ack=438 Win=1454 Len=0 #18 0.062053 192.168.1.103 192.168.1.2 HTTP HTTP/1.0 200 OK (GIF89a) TCP 80 > 1520 [PSH, ACK] Seq=1 Ack=438 Win=1454 Len=415
続いて、二回目のコネクションでブラウザが GIFファイル B.gif を要求します。 HTTP/1.1の時には、ここで、GIFファイルを要求するコネクションが二つ同時に飛んできたのですが、今回はひとつだけです。 GIFファイルを受信し終えて、コネクションの終了かと思っていたら、
#19 0.067185 192.168.1.2 192.168.1.103 TCP 1521 > 80 [SYN] Seq=0 Win=16384 Len=0 MSS=1460 #20 0.067542 192.168.1.103 192.168.1.2 TCP 80 > 1521 [SYN, ACK] Seq=0 Ack=1 Win=1454 Len=0 #21 0.067606 192.168.1.2 192.168.1.103 TCP 1521 > 80 [ACK] Seq=1 Ack=1 Win=16616 Len=0 #22 0.075055 192.168.1.2 192.168.1.103 HTTP GET /W.gif HTTP/1.1 TCP 1521 > 80 [PSH, ACK] Seq=1 Ack=1 Win=16616 Len=437 #23 0.076056 192.168.1.103 192.168.1.2 TCP 80 > 1521 [ACK] Seq=1 Ack=438 Win=1454 Len=0 #24 0.077340 192.168.1.103 192.168.1.2 HTTP HTTP/1.0 200 OK (GIF89a) TCP 80 > 1521 [PSH, ACK] Seq=1 Ack=438 Win=1454 Len=425
コネクションを終了させる前に二つ目のGIFファイル W.gif の要求が始まってしまいました。 GIFファイルを受け取って、今度は本当に通信終了だよね。
#25 0.168419 192.168.1.2 192.168.1.103 TCP 1520 > 80 [ACK] Seq=438 Ack=416 Win=16201 Len=0 #26 0.168786 192.168.1.103 192.168.1.2 TCP 80 > 1520 [FIN, ACK] Seq=416 Ack=438 Win=1454 Len=0 #27 0.168861 192.168.1.2 192.168.1.103 TCP 1520 > 80 [ACK] Seq=438 Ack=417 Win=16201 Len=0
次のパケットは、ブラウザから送信されます。 これは、#18に対する返答で、返答までに要した時間は、約0.1秒でした。 ColdFireは、#26でコネクション終了を宣言し、#27でブラウザが受信確認を送ります。
#28 0.269074 192.168.1.2 192.168.1.103 TCP 1521 > 80 [ACK] Seq=438 Ack=426 Win=16191 Len=0 #29 0.269476 192.168.1.103 192.168.1.2 TCP 80 > 1521 [FIN, ACK] Seq=426 Ack=438 Win=1454 Len=0 #30 0.269553 192.168.1.2 192.168.1.103 TCP 1521 > 80 [ACK] Seq=438 Ack=427 Win=16191 Len=0
続いて、#24に対する返答が#28で返されます。 返答までの所要時間は、0.2秒です。 ColdFireは、#29でコネクション終了を宣言し、ブラウザが#30で受信確認します。
#31 5.933938 192.168.1.2 192.168.1.103 TCP 1520 > 80 [FIN, ACK] Seq=438 Ack=417 Win=16201 Len=0 #32 5.934275 192.168.1.103 192.168.1.2 TCP 80 > 1520 [ACK] Seq=417 Ack=439 Win=1454 Len=0 #33 5.934329 192.168.1.2 192.168.1.103 TCP 1521 > 80 [FIN, ACK] Seq=438 Ack=427 Win=16191 Len=0 #34 5.934683 192.168.1.103 192.168.1.2 TCP 80 > 1521 [ACK] Seq=427 Ack=439 Win=1454 Len=0
ここから、前の実行結果と多少異なっています。 ブラウザが"FIN"を送信するのは、5.5秒後です。 前回は、8秒かかっていました。 また、ColdFireも今回は、"FIN"に対して"ACK"を確実に返しています。 そのため、パケットの送受信は、ここで終了します。
本日の考察
- httpサーバをHTTP1.0にダウン・グレードすると、ブラウザは同時に複数の通信を要求する振る舞いはしない。
- ただし、データ転送が終了した後でもコネクションは張られたままなので、複数コネクションを行っているようにも見える。
- ブラウザが"FIN"を発行するタイミングが早いので、ColdFireは、"ACK"で応える事が出来る。
GIFファイルの数をもっと増やしたらどうなるんでしょうね。
参考文献
Interface (インターフェース) 2008年 09月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/07/25
- メディア: 雑誌
ColdFireマイコンがネットワークにつながらない!? [ColdFire V2]
Interface 付録ColdFire基板特設ページで ColdFireマイコンがネットワークにつながらない!?が 公開されています。 『「ColdFireマイコンがネットワークにつながらない!」という問い合わせをいただきます。』って、問い合わせは違反じゃなかったの?
実装したRJ-45コネクタには本誌推奨の部品を使っていますか?
使ってませ~ん。 非推奨部品のSI-60001-F を使ってま~す。
久々にdigi-keyに確認に行ったら、「SI-60002-F」は、今なら在庫があるそうです。 その代わりに「SI-60001-F」の方が在庫切れだそうな。
クロスケーブルでパソコンとColdFireマイコン基板を直結していますか?
まだ、家庭内LANにつなぐのも怖いので、クロスケーブル専門です。 気が向いたら、スイッチング・ハブを使うこともあります。 間にスイッチング・ハブが入っていると、ColdFireの電源を落としても「ケーブルがつながっていません。」の表示が出てこなくなります。
パケット・モニタには、リピータ・ハブが良いと聞きましたが、市販品はスイッチング・ハブばかり。 まだ入手可能なのだろうか?
接続したパソコンのOSはVistaですか?
"Vista"って、リリースされてからずいぶん経ちますが、いい所あるんですか? 私は、もちろん、Windows XP SP2 です。
ファイヤーウォール/ウィルスチェックソフトなどはインストールしていますか?
どちらもインストールしていますが、逐一、警告が出てくれるから、これが原因で問題が発生したことはないですね。 設定が甘すぎるのかな?
可能であればOSを(HDDフォーマットから)再インストールして、
そこまで要求されるとは、思っていませんでした。
OS標準添付のツール以外には何もインストールされていない環境を用意し、
OS標準添付ツールには問題が無いみたいな書き方ですが、Vistaで問題を起こしたのは、Windows標準添付の「ナンチャッテ」ファイア・ウォールですよね。 アプリケーションさえ対応していれば、Windowsなんて捨てて、軽量な真のオペレーティングシステムに乗り換えちゃうのにな。
参考文献
Interface (インターフェース) 2008年 09月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/07/25
- メディア: 雑誌
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
- メディア: 雑誌
HTTPサーバのCGI機能を極める [ColdFire V2]
付録基板のHTTPサーバには、CGIの機能が装備されているので、調べてみました。 コレを使えば、XXXをXXXすることだって、できるよね。
HTML文書に長い文字列を埋めてみた
このHTTPサーバのCGI機能は、html文書からSilentCの関数を呼び出して、その出力を埋め込むという仕掛けです。 表を作成する関数を呼び出したところ、途中で打ち切られて最後まで出してくれません。 原因を調べるために、簡単な出力を出す関数を用意しました。
s(){PrStr("----+----1----+----2----+----3"); PrStr("----+----4----+----5----+----6"); PrStr("----+----7----+----8----+----9"); PrStr("----+----0");}
100バイトの目盛り付き文字出力を行います。 この関数を"Page1"というファイルに入れて使います。 HTML文書は、こんなものです。
<html><body><pre> $EXEC'Page1::s' </pre></body></html>
"Page1.htm"というファイルに入れて、HTTPサーバに表示させたところ、こんな出力が出てきました。
<html><body><pre> ----+----1----+ </pre></body></html>
わずかに15文字で打ち切られてしまいました。 表を作るなんて、とんでもないという長さです。
呼び出し方を変えたら
表作成関数を呼び出した時に打ち切られたのは、もっと長い文字数でした。 関数の呼び出し方に問題があるのかもしれないと考えて、括弧を加えてみました。
<html><body><pre> $EXEC'Page1::s()' </pre></body></html>
<html><body><pre> ----+----1----+-- </pre></body></html>
すると、こんどは、17文字になりました。
つまり、これは、$EXEC'Page1::s()'
という文字列の長さと同じです。
このHTTPサーバのCGI機能とは、元のファイルの該当箇所を「置き換える」機能だったようです。
呼び出し方をムダに長くする
だったら、関数呼び出し側の文字数をもっとムダに長くすれば、解決ですね。
<html><body><pre> $EXEC'Page1::s( 0, 0, 0)' </pre></body></html>
本当は、括弧の中に空白を並べるだけで十分なのですが、記事にすると見えなくなるので、引数として表現しています。 このHTML文書を使うと、こんな出力が得られました。
<html><body><pre> ----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8- 0)' </pre></body></html>
埋め込む場所は、十分に用意したはずなのに、81文字で打ち切られてしまいました。 内部処理で準備されたバッファの長さの限界ということでしょうか。 おまけに、コンソールにゴミが出力されて、時には暴走してしまいます。 何か、壊しちゃったみたいですね。
本日の考察
- HTTPサーバのCGI機能は、元の文書の該当箇所を置き換える機能である。
- CGI機能で長い文字列を出したいときには、元の文書で場所を確保しておかなくてはならない。
- 置き換えられる文字数は、81文字が限界で、これ以上長くすると暴走の危険がある。ただし、81文字であれば絶対に安全かという検証はしていない。
どうやら、この置き換えの作業をしているのが、"ReplaceCgi"という関数のようです。 このCGI機能で表を作成するのは、難しそうだな。
参考文献
Interface (インターフェース) 2008年 09月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/07/25
- メディア: 雑誌
SilentCの関数一覧表 (3) [ColdFire V2]
SilentCの関数一覧表を作成しました。 コメント!--も合わせてお読みください。
SilentC 関数一覧表 (3)
関数 | 返り値 |
---|---|
long Atoi(char *buf) | |
char Bind(char socket, int port, char maxsoc) |
|
char Accept(char socket, int timeout) |
|
int GetSenderPort(char socket) |
|
long GetSenderIP(char socket) |
|
int SendTo(char socket, long ip, int port, char *buf, int len) | |
int RecvFrom(char socket, int timeout) |
|
int DoCgi(char *ptr) | 0 |
char *ReplaceCgi(long p4, int p10) | |
int GetDefMtu(char socket, int size) |
|
long GetIP(char *ipstr) | |
long UserDriver(char vector, long arg) | D0 |
char SmartInit(void) | |
char SmartErase(char xxx) | |
char SmartWrite(int page, char offset, char *buf, int size) | |
int SmartRead(int page, char offset, char *buf, int size) | |
char NvmWrite(char *addr, char *buf, int size) | CFMUSTAT |
char NvmErase(char *addr) | CFMUSTAT |
FirmwareUpdate(long checksum) | N/A |
long Checksum(char *buf, long size) | checksum |
char InitAd(char portmask) | 0 |
int GetAd(char channel) |
"SmartXxxx"関数は、今のところ未解明。
"NvmWrite"関数と"NvmErase"関数は、安全のため(?)SilentCが存在する0x20000よりも小さいアドレスを指定することが出来ない。 しかし、これには抜け道があって、0xFFF00000からのアドレスを指定すると、0x00000000からのアドレスに変換される。 例えば、NvmWrite(0xfff000fc,&d,4);とすると、0x000000FC番地に値を書き込むという危ない操作が出来る。
"InitAd"関数では、A/D変換クロックを「CTRL2[DIV]=3」と設定している。 この設定によるとA/D変換クロックは「60MHz/8=7.5MHz」となるので、仕様上の上限である5MHzを超えるのではないだろうか。 試しにA/D変換クロックを上下させたが、目に見える影響は無かった。
"GetAd"関数は、一回の呼出しごとに10ミリ秒の変換待ちをしている。 このため、どんなにがんばっても毎秒100サンプルのデータしか得ることが出来ない。 このあたり、ColdFire×P2P地震情報(7) "33.3 Hzの壁"を超えるの記述と符合する。
参考文献
Interface (インターフェース) 2008年 09月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/07/25
- メディア: 雑誌
SilentCの知られざる世界 (1) [ColdFire V2]
SilentCの関数にInterface誌の記述との相違点を見つけました。
SciPutc関数
"SciPutc"関数は、UART0から一文字分のデータを送信する機能です。 Interface誌には、引数をひとつ取る関数として記述されています。
void SciPutc(char ch)
ところが、この記述を信じて関数を使用したところ、文字が表示されません。
OK SciPutc('*') OK
さる所を調査した結果、第二引数の値が表示されるらしいことが判明しました。
OK SciPutc('A', '*') * OK
第一引数は、使用されていないように見えます。
ファイル・ハンドルはlong型である
Interface誌には、ファイル・ハンドルは"int"型、すなわち16ビットであると記述されています。 ところが、"OpenFile"関数は、32ビットの値を返してきます。
OK ??OpenFile("index.htm") 20001370 OK
まず、ファイル・ハンドルが32ビットであると仮定して、"SeekFile"関数でファイルの終端にポインタを移動してみました。
OK ?SeekFile(0x20001370,0,2) 409 OK
409というのは、"index.htm"ファイルの長さと等しいので、ファイルの終端にポインタが移動したらしいことがわかります。
もし、これを16ビットの変数に代入して使ったら、どうなるでしょうか。
OK ?SeekFile(0x1370,0,2) 317948 OK
これは、何が起こったのでしょうか。 317kバイトもポインタが移動してしまったことになっています。
参考文献
Interface (インターフェース) 2008年 09月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/07/25
- メディア: 雑誌
SilentCの関数一覧表 (2) [ColdFire V2]
SilentCの関数一覧表を作成しました。 コメント!--も合わせてお読みください。
SilentC 関数一覧表 (2)
関数 | 返り値 |
---|---|
int FormatFilesys(int key) | 0 |
int DefragFilesys(int key) | 0 |
long GetFilnalPos(void) | |
char CreateFile(char *name) |
|
int WriteFile(char *buf, int size) | |
int CloseFile(long handle) | |
char DeleteFile(char *name) | |
char MoveFile(char *oldname, char *newname) | |
char *FindFile(char init) | |
long GetFileSize(char *name) | |
long OpenFile(char *name) | ファイル構造体のアドレス |
int ReadFile(long handle, char *buf, int size) | |
long SeekFile(long handle, long pos, char org) | 設定後の位置 |
int FileGets(long handle, char *buf, long size) | 読み込んだバイト数 |
int FilePuts(char *str) | 書き込んだバイト数 |
int GetDigit(long num, char *buf) | 0 |
char SciSense(void) | 1 or 0 |
char SciGetc(void) | 入力文字 |
int SciPutc(long X, char ch) | 0 |
int SciPuts(char *str) | 0 |
int SciGets(char *buf, long max) | 受信バイト数 |
int Gets(char *buf, long len) |
|
char Getc(long wait) |
|
"CreateFile"関数が返してくる値は、0から5まで用意されているが、詳細は未解明である。
"OpenFile"関数が返してくるファイル・ハンドルは、ファイル構造体のアドレスである。 このため、"int"ではなく"long"でなくてはならない。 同様に"CloseFile"関数などで使用されるファイル・ハンドルも"long"である。
"FileGets"関数の引数sizeは、"long"で与えられるが、内部では、符号無し8ビットとして使われている。 しかも、実際に読み込んだ文字数は、16ビットで数えられていて、返り値に使用されている。
"SciPutc"関数の引数"char ch"は、第二引数で与えられているように見える。 実際に第二引数が表示されるのを確認した。
"SciGets"関数の引数maxは、"long"で与えられるが、内部では符号無し8ビットとして使われている。
参考文献
Interface (インターフェース) 2008年 09月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/07/25
- メディア: 雑誌
TCP受信ルーチンにSystemSleepを散りばめる [ColdFire V2]
"masato"さんより、「SystemSleep()を入れたら、うまくいくかも。」というコメントをもらいました。 早速、試してみよう。
SystemSleep()を散りばめた
「ループ内に入れる」という情報しかないので、たくさん入れてしまいました。
sum = 0; for (;;) { len = Read(socket,1000); if (len < 0) break; SystemSleep(); buf = GetReceiveBuffer(socket,1); SystemSleep(); MemoryFree(buf); SystemSleep(); PrHexWord(len);PrStr(" "); SystemSleep(); sum += len; } PrHexWord(len);PrStr(" ");PrNum(sum);
これで、オペレーティングシステムの仕事が優先になって、パケットを受信してくれることでしょう。 本当に?
コネクションの確立
パケット・モニタを仕掛けて、実行してみました。 手順は、前回と同じです。
#1 0.000000 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [SYN] Seq=0 Win=1454 Len=0 #2 0.000171 192.168.1.2 192.168.1.10 TCP 30049 > 1024 [SYN, ACK] Seq=0 Ack=1 Win=16616 Len=0 MSS=1460 #3 0.000540 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [ACK] Seq=1 Ack=1 Win=1454 Len=0
コネクションの3ウェイ・ハンドシェイクは、変わりありません。
100バイトの受信
> 100 0064 fffe 100
#4 4.157214 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [PSH, ACK] Seq=1 Ack=1 Win=1454 Len=4 #5 4.157724 192.168.1.2 192.168.1.10 TCP 30049 > 1024 [PSH, ACK] Seq=1 Ack=5 Win=16612 Len=100 #6 4.158245 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [ACK] Seq=5 Ack=101 Win=1454 Len=0
100バイトの受信も問題ありません。
1600バイトの受信
次は、いよいよ、1660バイトの受信です。
> 1600 0218 0218 0210 fffe 1600
1600バイトの受信自体は、できました。 しかし、1セグメント受け取るのに2~3秒かかっているので、表示がポツリポツリ出てきます。 原因をパケット・モニタで調べます。
#7 17.372065 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [PSH, ACK] Seq=5 Ack=101 Win=1454 Len=5 #8 17.372573 192.168.1.2 192.168.1.10 TCP 30049 > 1024 [ACK] Seq=101 Ack=10 Win=16607 Len=536 #9 17.372603 192.168.1.2 192.168.1.10 TCP 30049 > 1024 [ACK] Seq=637 Ack=10 Win=16607 Len=536 #10 17.373773 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [ACK] Seq=10 Ack=637 Win=1454 Len=0 #11 17.373857 192.168.1.2 192.168.1.10 TCP 30049 > 1024 [PSH, ACK] Seq=1173 Ack=10 Win=16607 Len=528
クライアントからの要求(#7)に対して、サーバが三つのセグメント(#8, #9, #11)を一度に送ってきて、それに対してクライアントからの返答(#10)が#8に対応するものしか戻ってこない。 ここまでは今までと同じです。
ここで、前回は#9に対する応答をスキップして#11に対する応答を返していました。 ところが、今回は、クライアントからは受信確認が出てきません。
#12 19.111843 192.168.1.2 192.168.1.10 TCP [TCP Retransmission] 30049 > 1024 [ACK] Seq=637 Ack=10 Win=16607 Len=536 #13 19.113008 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [ACK] Seq=10 Ack=1173 Win=1454 Len=0
サーバは、クライアントからの受信確認が届かないので、約2秒後に#12で#9の再送を試みます。 これに対して、クライアントは、#13で受信確認を返します。 この間、1.2ミリ秒です。 PCとの間は、クロスケーブルでつないでいるので、確かにSilentCからの応答です。
#14 19.113094 192.168.1.2 192.168.1.10 TCP [TCP Retransmission] 30049 > 1024 [PSH, ACK] Seq=1173 Ack=10 Win=16607 Len=528 #15 22.934174 192.168.1.2 192.168.1.10 TCP [TCP Retransmission] 30049 > 1024 [PSH, ACK] Seq=1173 Ack=10 Win=16607 Len=528 #16 22.935341 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [ACK] Seq=10 Ack=1701 Win=1454 Len=0
受信確認に気を良くしたサーバは、#11の再送として#14を送りますが、やはりクライアントからの受信確認が届きません。 サーバは、約2秒後に再々送として、#15を送り、無事、クライアントから受信確認(#16)を受け取ります。
以上のような状況から、通信が成立した理由は、単にクライアントが受信確認を出すヒマが無かったためと考えられます。 「#12から#13まで」と「#15から#16まで」の処理時間は、どちらもわずかに1.2ミリ秒です。 そのため、到着したセグメントを取り込む前に受信確認パケットを送ってしまったのではないかと推測します。 そして、結果として次のパケットの受信が間に合わなかったのではないでしょうか。
再度、1600バイトの受信
再度、1600バイトの受信を試みます。 さっき、あれだけ再送が必要だったのだから、今度は手加減してくれるかも。
> 1600 0218 0218 0210 fffe 1600
今度も、ちんたらした受信です。
#17 36.905815 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [PSH, ACK] Seq=10 Ack=1701 Win=1454 Len=5 #18 36.906323 192.168.1.2 192.168.1.10 TCP 30049 > 1024 [ACK] Seq=1701 Ack=15 Win=16602 Len=536 #19 36.906357 192.168.1.2 192.168.1.10 TCP 30049 > 1024 [ACK] Seq=2237 Ack=15 Win=16602 Len=536 #20 36.907498 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [ACK] Seq=15 Ack=2237 Win=1454 Len=0 #21 36.907557 192.168.1.2 192.168.1.10 TCP 30049 > 1024 [PSH, ACK] Seq=2773 Ack=15 Win=16602 Len=528 #22 38.323103 192.168.1.2 192.168.1.10 TCP [TCP Retransmission] 30049 > 1024 [ACK] Seq=2237 Ack=15 Win=16602 Len=536 #23 38.324225 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [ACK] Seq=15 Ack=2773 Win=1454 Len=0 #24 38.324298 192.168.1.2 192.168.1.10 TCP [TCP Retransmission] 30049 > 1024 [PSH, ACK] Seq=2773 Ack=15 Win=16602 Len=528 #25 41.341667 192.168.1.2 192.168.1.10 TCP [TCP Retransmission] 30049 > 1024 [PSH, ACK] Seq=2773 Ack=15 Win=16602 Len=528 #26 41.342827 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [ACK] Seq=15 Ack=3301 Win=1454 Len=0
内容も全く同じです。
1600バイトの受信、三度目
淡い期待を抱いて、三度目の受信に挑戦します。
> 1600 0218 0218 0210 fffe 1600
やっぱり、受信状況は変わらず。
#27 62.418165 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [PSH, ACK] Seq=15 Ack=3301 Win=1454 Len=5 #28 62.418663 192.168.1.2 192.168.1.10 TCP 30049 > 1024 [ACK] Seq=3301 Ack=20 Win=16597 Len=536 #29 62.418699 192.168.1.2 192.168.1.10 TCP 30049 > 1024 [ACK] Seq=3837 Ack=20 Win=16597 Len=536 #30 62.421627 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [ACK] Seq=20 Ack=3837 Win=1454 Len=0 #31 62.421704 192.168.1.2 192.168.1.10 TCP 30049 > 1024 [PSH, ACK] Seq=4373 Ack=20 Win=16597 Len=528 #32 63.571481 192.168.1.2 192.168.1.10 TCP [TCP Retransmission] 30049 > 1024 [ACK] Seq=3837 Ack=20 Win=16597 Len=536 #33 63.572649 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [ACK] Seq=20 Ack=4373 Win=1454 Len=0 #34 63.572737 192.168.1.2 192.168.1.10 TCP [TCP Retransmission] 30049 > 1024 [PSH, ACK] Seq=4373 Ack=20 Win=16597 Len=528 #35 65.985579 192.168.1.2 192.168.1.10 TCP [TCP Retransmission] 30049 > 1024 [PSH, ACK] Seq=4373 Ack=20 Win=16597 Len=528 #36 65.986743 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [ACK] Seq=20 Ack=4901 Win=1454 Len=0
パケットの内容も全く同じでした。
蛇足:コネクション終了
せっかくだから、コネクションの終了も記録しておきます。
> q QUIT detected
クライアント側のプログラムは、"q"で始まる行を入力すると、コネクションを切断します。
#37 79.311295 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [FIN, ACK] Seq=20 Ack=4901 Win=1454 Len=0 #38 79.311430 192.168.1.2 192.168.1.10 TCP 30049 > 1024 [ACK] Seq=4901 Ack=21 Win=16597 Len=0 #39 79.311542 192.168.1.2 192.168.1.10 TCP 30049 > 1024 [FIN, ACK] Seq=4901 Ack=21 Win=16597 Len=0 #40 79.311888 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [ACK] Seq=21 Ack=4902 Win=1454 Len=0
これは、問題なさそうです。
本日の考察
以上の実験から、以下の事柄が判明しました。
- SilentCは、受信したセグメントの処理が終わらないうちに、早々に受信確認を送っているように見える。結果として、さっさと次のセグメントが送られてきてしまい、受信に失敗しているので、自分で自分の首を絞めているのではないか。
- PCは、再送が必要になるような信頼性の低い通信路であることを認識すべきなのに、手加減せずにパケットを送りつけてくる。これは、クライアントが常に主張している1454バイトのウィンドウ・サイズと関連するのかもしれない。
参考文献
Interface (インターフェース) 2008年 09月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/07/25
- メディア: 雑誌
ネットワークマガジン 2004年2月号 特集1 徹底図解 はじめての「プロトコル」
「過去記事PDF」が入っている付録CD-ROMを引っ張り出してきました。
TCP通信の監視にパケット・モニタを使ってみよう [ColdFire V2]
付録基板とのTCP通信でデータの欠損が出ることがわかりました。 なぜ、欠損が発生するかを調べるために、パケット・モニタを入れてみました。
あ~あ、またインストールしちゃったよ。
パケット・モニタって、こんなもの
パケット・モニタとは、ネットワークに流れるパケットを捕まえてログを作成するものと私は理解しています。 本格的なハードウェアなら、本当にネットワークの配線に仕掛けるべきなのですが、さすがにそこまでの出費は出来ません。 しかし、PCのetherポートを監視するソフトウェアであれば、拾ってくることも出来ます。 この場合、PCに出入りするパケットしか監視できませんが、まあ、十分でしょう。
今回インストールしたのは、Wiresharkという名前の洋物ソフトウェアです。
接続、点火(?)
サーバ側プログラムをPCで立ち上げた所から監視を開始しました。 SilentCのプログラムを走らせると、TCPによるコネクションが確立されます。
#3 time=15.463291 from=192.168.1.10 to=192.168.1.2 TCP 1024 > 30049 [SYN] Seq=0 Win=1454 Len=0 #4 time=15.463458 from=192.168.1.2 to=192.168.1.10 TCP 30049 > 1024 [SYN, ACK] Seq=0 Ack=1 Win=16616 Len=0 MSS=1460 #5 time=15.463789 from=192.168.1.10 to=192.168.1.2 TCP 1024 > 30049 [ACK] Seq=1 Ack=1 Win=1454 Len=0
まあ、軽いご挨拶ですね。
100バイトのデータを要求した
最初は、100バイトの小さいデータを要求してみました。
> 100 0064 fffe 100
#6 21.353930 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [PSH, ACK] Seq=1 Ack=1 Win=1454 Len=4 #7 21.354438 192.168.1.2 192.168.1.10 TCP 30049 > 1024 [PSH, ACK] Seq=1 Ack=5 Win=16612 Len=100 #8 21.354945 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [ACK] Seq=5 Ack=101 Win=1454 Len=0
#6で、"100\r"という4バイトのデータをクライアントからサーバに送ります。 すると、サーバからは、#7として、受信確認(ACK)兼データがクライアントに送られてきます。 クライアントは、#8で受信確認(ACK)をサーバに送ります。
このとき、#7のSeq=1とLen=100を足した値がAck=101に入ってくるので、サーバは、100バイトのデータが受信されたことを確認することが出来るという仕組みです。
1600バイトのデータを要求したら
次に、1600バイトの大きなデータを要求します。
> 1600 0218 0210 fffe 1064
#9 33.774452 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [PSH, ACK] Seq=5 Ack=101 Win=1454 Len=5 #10 33.775003 192.168.1.2 192.168.1.10 TCP 30049 > 1024 [ACK] Seq=101 Ack=10 Win=16607 Len=536 #11 33.775031 192.168.1.2 192.168.1.10 TCP 30049 > 1024 [ACK] Seq=637 Ack=10 Win=16607 Len=536 #12 33.778026 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [ACK] Seq=10 Ack=637 Win=1454 Len=0
#9で、クライアントからサーバに"1600\r"という5バイトのデータが送信されます。 これに対して、サーバは、1600バイトのデータを三つに分割し、#10と#11で536バイトずつのデータを連続して送ります。 その間隔は、わずかに30マイクロ秒です。 クライアントは、#10に対する応答を#12で返します。 #12のAck=637が、#10のSeq=101とLen=536の和になっていることから#10に対する応答であることがわかります。 この時点では、#11に対する応答は、まだPCに届いていません。
#13 33.778113 192.168.1.2 192.168.1.10 TCP 30049 > 1024 [PSH, ACK] Seq=1173 Ack=10 Win=16607 Len=528 #14 33.783299 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [ACK] Seq=10 Ack=1701 Win=1454 Len=0
続いて、サーバからは#13で最後の528バイトが送信されてきます。 その後、#14でAck=1701の応答をクライアントが返しています。 Ack=1701は、#13のSeq=1173とLen=528の和なので、#13に対する応答です。
これで、一連の通信は終わってしまいました。 あれ? #11に対する応答がありません。 SilentCの出力したログを見ても、二つ目のパケットを受け取ったとは思っていないことがわかります。 この場合、サーバは、#11のデータを再送するんじゃないのかな?
受信確認がスキップされたとしても、TCPのプロトコルとしては正しいのだそうです。 問題は、SilentCが受信したことを認識していないことです。
また、クライアントが送っているパケット(セグメント?)には、いつもWin=1454が付いています。 536バイトのデータを受信していても、ウィンドウの値は1454のままです。 これを信じたサーバが山のようにパケットを送ってくるようにならないのでしょうか。
1600バイトのデータを要求して、再送が発生した
続いて、1600バイトのデータを再度要求してみました。
> 1600 0218 0218 fffe 1072
#15 46.617221 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [PSH, ACK] Seq=10 Ack=1701 Win=1454 Len=5 #16 46.617718 192.168.1.2 192.168.1.10 TCP 30049 > 1024 [ACK] Seq=1701 Ack=15 Win=16602 Len=536 #17 46.617753 192.168.1.2 192.168.1.10 TCP 30049 > 1024 [ACK] Seq=2237 Ack=15 Win=16602 Len=536 #18 46.618920 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [ACK] Seq=15 Ack=2773 Win=1454 Len=0 #19 46.619007 192.168.1.2 192.168.1.10 TCP 30049 > 1024 [PSH, ACK] Seq=2773 Ack=15 Win=16602 Len=528
クライアントからの#15の要求に対して、サーバから#16、#17、#19と三つのセグメントが送られてきます。 クライアントは、#18で受信確認を返します。 この受信確認は、Ack=2773なので、#17のSeq=2237、Len=536に対する応答で、#16に対する応答はPCに届いていません。
#20 46.625991 192.168.1.10 192.168.1.2 TCP [TCP Dup ACK 18#1] 1024 > 30049 [ACK] Seq=15 Ack=2773 Win=1454 Len=0 #21 47.752636 192.168.1.2 192.168.1.10 TCP [TCP Retransmission] 30049 > 1024 [PSH, ACK] Seq=2773 Ack=15 Win=16602 Len=528 #22 47.753711 192.168.1.10 192.168.1.2 TCP [TCP Dup ACK 18#2] 1024 > 30049 [ACK] Seq=15 Ack=2773 Win=1454 Len=0 #23 47.753795 192.168.1.2 192.168.1.10 TCP [TCP Fast Retransmission] 30049 > 1024 [PSH, ACK] Seq=2773 Ack=15 Win=16602 Len=528 #24 47.754853 192.168.1.10 192.168.1.2 TCP [TCP Dup ACK 18#3] 1024 > 30049 [ACK] Seq=15 Ack=2773 Win=1454 Len=0 #25 50.067080 192.168.1.2 192.168.1.10 TCP [TCP Retransmission] 30049 > 1024 [PSH, ACK] Seq=2773 Ack=15 Win=16602 Len=528 #26 50.068148 192.168.1.10 192.168.1.2 TCP [TCP Dup ACK 18#4] 1024 > 30049 [ACK] Seq=15 Ack=2773 Win=1454 Len=0 #27 54.895261 192.168.1.2 192.168.1.10 TCP [TCP Retransmission] 30049 > 1024 [PSH, ACK] Seq=2773 Ack=15 Win=16602 Len=528 #28 54.896348 192.168.1.10 192.168.1.2 TCP [TCP Dup ACK 18#5] 1024 > 30049 [ACK] Seq=15 Ack=2773 Win=1454 Len=0
この後、#20でクライアントがサーバに受信確認を送りますが、この受信確認はAck=2773なので、#19に対する応答ではなく、#17のSeq=2237、Len=536に対する応答です。 そのため、サーバからは何度も#19の再送データが送られてきます。 ところが、それに対してクライアントが送るのは、#17に対する応答です。
クライアントが、受信していないと言い張ることで、サーバは、あきらめてしまったのか、再送も止めてしまいます。 結局、この通信は、不成立になったはずなのですが、サーバもクライアントもプログラムは走り続けます。 変なの。
1600バイトのデータを要求して1600バイトのデータを受け取った
何度か試しているうちに、1600バイトのデータを受信できたケースも出てきました。
> 1600 0218 0218 0210 fffe 1600
#51 83.980854 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [PSH, ACK] Seq=25 Ack=5973 Win=1454 Len=5 #52 83.981367 192.168.1.2 192.168.1.10 TCP 30049 > 1024 [ACK] Seq=6501 Ack=30 Win=16587 Len=536 #53 83.982514 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [ACK] Seq=30 Ack=7037 Win=1454 Len=0 #54 83.982581 192.168.1.2 192.168.1.10 TCP 30049 > 1024 [ACK] Seq=7037 Ack=30 Win=16587 Len=536 #55 83.982606 192.168.1.2 192.168.1.10 TCP 30049 > 1024 [PSH, ACK] Seq=7573 Ack=30 Win=16587 Len=528
クライアントの要求(#51)に対して、サーバは#52のデータを送ります。 サーバが#54で次のセグメントを送る前に、クライアントは#53の受信応答を送ることが出来ました。 サーバは、#54に続いて#55で三つ目のセグメントを送ります。
#56 84.568419 192.168.1.2 192.168.1.10 TCP [TCP Retransmission] 30049 > 1024 [ACK] Seq=7037 Ack=30 Win=16587 Len=536 #57 84.569592 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [ACK] Seq=30 Ack=7573 Win=1454 Len=0 #58 84.569681 192.168.1.2 192.168.1.10 TCP [TCP Retransmission] 30049 > 1024 [PSH, ACK] Seq=7573 Ack=30 Win=16587 Len=528 #59 84.574613 192.168.1.10 192.168.1.2 TCP 1024 > 30049 [ACK] Seq=30 Ack=8101 Win=1454 Len=0
ところが、#54、#55に対する受信応答がクライアントから発信されません。 サーバは、約0.5秒後に#56で#54のセグメントを再送し、クライアントは#57で受信確認します。 さらに、サーバは、#58で#55のセグメントを再送し、クライアントが#59で受信確認します。
このように、サーバが再送信を行えば通信が成り立ち、クライアントはすべての受信することができます。
本日の考察
以上の結果から、以下の事柄が判明、推測されました。
- SilentCから送信されるパケットのウィンドウサイズは、いつも1454バイトである。
- 受信確認(ACK)が届いていないにもかかわらず、PCからセグメントが再送されない場合がある。
- SilentCが送信するべき受信確認パケットが「しばしば」届かない。
- 再送信セグメントに対するSilentCの応答が不適切な場合がある。
- パケットひとつひとつに対してハンド・シェイクを行えば、欠損無く通信ができるらしい。
参考文献
Interface (インターフェース) 2008年 09月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/07/25
- メディア: 雑誌
Read関数の最大受信サイズを調べる [ColdFire V2]
Read関数で大きなデータを受信するプログラムを作成しました。 この基板でネットワークらしいプログラムを組むのは、初めてだな。
サーバ側プログラムは、Javaで組んだ
実験を行うにあったって、サーバのプログラムをJavaで組みました。 送信されてきた数値に相当する長さのアスタリスクで埋め尽くされた文字列を送り返します。 簡単なプロトコルなので、telnetを使って、会話することも出来ます。
/* * -------------------------------------------- * File : TcpEchoServer.java * Package : org.noritan.tcpecho * Copyright : Copyright (c) 2008 noritan.org * Organization : noritan.org * Created : 2008/09/22 * -------------------------------------------- */ package org.noritan.tcpecho; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; /** * ThisTcpEchoServer
class is a server * to send a packet to the client regarding the client's * request sent by a received packet. * * @author noritan */ public class TcpEchoServer implements Runnable { private int port; /** * Construct aTcpEchoServer
object. * * @param port * a port number to wait for a clinet. */ public TcpEchoServer(int port) { this.port = port; } /** * A server process method. * This server accepts only one client at once and * quits when the connection has been closed. * * @see java.lang.Runnable#run() */ public void run() { try { // Create a server socket at a specified port. ServerSocket server = new ServerSocket(port); try { for (;;) { // Wait for a client. // Only one client can be accepted. Socket socket = server.accept(); System.out.println("Connected by " + socket.getInetAddress()); System.out.println("SEND BUFFER="+socket.getSendBufferSize()); try { echoback( socket.getInputStream(), socket.getOutputStream()); } catch (IOException ex) { System.out.println("Failed to get streams"); } finally { try { socket.close(); } catch (IOException ex) { // do nothing for close } System.out.println("Socket closed"); } } } catch (IOException ex) { System.out.println("Failed to accept a socket"); ex.printStackTrace(); } finally { try { server.close(); } catch (IOException ex) { // do nothing for close. } } } catch (IOException ex) { System.out.println("Failed to open a server"); ex.printStackTrace(); } } /** * Send a echo-back using a specified input * and output streams. * * @param inputStream * An InputStream to get a request from a client. * @param outputStream * An OutputStream to send an echo to a client. */ private void echoback( InputStream inputStream, OutputStream outputStream ) { BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(inputStream) ); for (;;) { String line; try { // Get a line line = bufferedReader.readLine(); // Quit the loop at EOF if (line == null) break; } catch (IOException ex) { System.out.println("Failed to read a line"); break; } System.out.println("REQUEST="+line); try { outputStream.write(createReply(line)); } catch (IOException ex) { System.out.println("Failed to send a packet"); } finally { try { outputStream.flush(); } catch (IOException ex) { // do nothing for flush } } System.out.println("Reply sent"); } } /** * Create a reply to the client regarding the * request from the client. * * @param request * Request received by the client. * @return * Reply to the clinet inbyte[]
*/ private byte[] createReply(String request) { byte[] buffer; int length = 1; // default length try { // Get a request as a packet size. length = Integer.parseInt(request); } catch (NumberFormatException ex) { System.out.println("Not a number"); } // Create a reply, a specified size of packet // Filled with * buffer = new byte[length]; for (int i = 0; i < length; i++) { buffer[i] = '*'; } return buffer; } /** * Invoke a server thread. * * @param args * No arguments are used. */ public static void main(String[] args) { new Thread(new TcpEchoServer(30049)).start(); } }
クライアント側プログラムは、SilentCで組んだ
クライアント側のプログラムは、われらがSilentCで組みました。 コンソールから入力された文字列に行末文字を追加してサーバに送り、返答を受け取ります。 返答された内容は、捨ててしまい、Read関数が返してきた値だけを記録していきます。 Read関数では、タイムアウト時間として10秒待ち、エラーコードが返ってくるまで受信を試みます。 すべてのデータを検出するためにわざと長いタイムアウト時間を使っています。
main(){ char socket; char *host = "192.168.1.2"; char *line = MemoryAlloc(32); int len; long sum; char *buf; do { socket = CreateSocket(1); do { if (Connect(socket,GetHostByName(host),30049) < 0) { PrStr("Failed to connect\r\n"); break; } for (;;) { PrStr("\r\n> "); Gets(line,16); if (line[0] == 'q') { PrStr("QUIT detected\r\n"); break; } StrCat(line,"\n"); if (Write(socket,line,StrLen(line)) < 0) { PrStr("Failed to Write\r\n"); continue; } if (WaitWriteComplete(socket) < 0) { PrStr("Failed to Complete Write\r\n"); continue; } sum = 0; for (;;) { len = Read(socket,1000); if (len < 0) break; buf = GetReceiveBuffer(socket,1); MemoryFree(buf); PrHexWord(len);PrStr(" "); sum += len; } PrHexWord(len);PrStr(" ");PrNum(sum); } } while (0); CloseSocket(socket); } while (0); MemoryFree(line); }
プログラムの実行結果
今回は、UART0のコンソールを使って通信を行わせています。 プログラムを実行した結果、Javaでは一括で送っているつもりのデータをSilentCでは分割して受け取っていることが分かりました。
> 100 0064 fffe 100 > 200 00c8 fffe 200 > 400 0190 fffe 400 > 800 0218 0108 fffe 800
Read関数の返してきた値に加えて、エラー以外の値の合計を計算させて表示しています。 これによると、バッファの単位は、536($0218)のようです。 これは、誰が決めた値なんだろう?
データのサイズを大きくするとデータが足りなくなってしまうことが多くなります。
> 1600 0218 0210 fffe 1064 > 1600 0218 0210 fffe 1064 > 1600 0218 0218 fffe 1072 > 1600 0218 0218 0210 fffe 1600 > 1600 0218 0210 fffe 1064
SilentC側の処理を早くしてみる
これは、単にSilentC側でバッファがあふれているのだろうと考えて、あふれる前にデータを引き取ることが出来るようにプログラムを変更しました。
main(){ char socket; char *host = "192.168.1.2"; char *line = MemoryAlloc(32); char **bufTab = MemoryAlloc(64); long *lenTab = MemoryAlloc(64); long retval,sum,i,index; do { socket = CreateSocket(1); do { if (Connect(socket,GetHostByName(host),30049) < 0) { PrStr("Failed to connect\r\n"); break; } for (;;) { PrStr("\r\n> "); Gets(line,16); if (line[0] == 'q') { PrStr("QUIT detected\r\n"); break; } StrCat(line,"\n"); if (Write(socket,line,StrLen(line)) < 0) { PrStr("Failed to Write\r\n"); continue; } if (WaitWriteComplete(socket) < 0) { PrStr("Failed to Complete Write\r\n"); continue; } index = 0; for (;;) { retval = Read(socket,1000); if (retval < 0) break; lenTab[index] = retval; bufTab[index] = GetReceiveBuffer(socket,1); index++; } sum = 0; for (i=0;i<index;i++){ PrHexWord(lenTab[i]);PrStr(" "); sum += lenTab[i]; MemoryFree(bufTab[i]); } PrHexWord(retval);PrStr(" ");PrNum(sum); } } while (0); CloseSocket(socket); } while (0); MemoryFree(bufTab); MemoryFree(lenTab); MemoryFree(line); }
バッファを受け取るごとに行っていたバッファ領域の開放と表示を後回しにしました。 しかし、効果は無く、あいかわらずデータの欠損が見られます。
> 100 0064 fffe 100 > 200 00c8 fffe 200 > 400 0190 fffe 400 > 800 0218 0108 fffe 800 > 1600 0218 0210 fffe 1064 > 1600 0218 0210 fffe 1064 > 1600 0218 0210 fffe 1064 > 1600 0218 0210 fffe 1064 > 1600 0218 0218 0210 fffe 1600 > 1600 0218 0210 fffe 1064
こうなったら、メモリ・リーク覚悟で、バッファの保存を省いてしまおう。
index = 0; for (;;) { retval = Read(socket,1000); if (retval < 0) break; lenTab[index] = retval; GetReceiveBuffer(socket,1); index++; } sum = 0; for (i=0;i<index;i++){ PrHexWord(lenTab[i]);PrStr(" "); sum += lenTab[i]; } PrHexWord(retval);PrStr(" ");PrNum(sum);
結果は、ますますひどくなってしまったようです。
> 100 0064 fffe 100 > 200 00c8 fffe 200 > 400 0190 fffe 400 > 800 0218 fffe 536 > 1600 Failed to Complete Write
これは、サーバとクライアントが共にデータを送ろうとした結果、ハングしたものと思われます。
本日の結論
- "Read"関数には、127バイトを超えるデータを受信する能力がある。
- しかし、SilentCで大きなデータを受信するのは苦しい。バッファサイズの536バイトを上限としてボチボチ送ったほうが良さそうだ。
参考文献
Interface (インターフェース) 2008年 09月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/07/25
- メディア: 雑誌
TCP/IP解説書のお勧め募集中。
SilentCの関数一覧表 (1) [ColdFire V2]
SilentCの関数一覧表を作成しました。
関数名 | 返り値 |
---|---|
char *MemoryAlloc(int size) | メモリ・ブロック先頭 |
int BufCopy(void *dest, void *src, int size) | 0 |
int MemClear(void *dest, int size) | 0 |
char CheckWriteComplete(char socket) | |
char WaitWriteComplete(char socket) | |
char CloseSocket(char socket) | |
char Connect(char socket, long ip, int port) | |
int MemoryFree(void *memory) | 0 |
long GetHostByName(char *name) | IPアドレス |
char *GetReceiveBuffer(char socket, char release) | バッファ先頭 |
int PrAdrs(long adrs) | 0 |
int PrChar(char c) | 0 |
int PrHex(long num, ..) | 0 |
int PrHexWord(int num, ..) | 0 |
int PrHexByte(char num, ..) | 0 |
int PrNum(long num, ..) | 0 |
int PrStr(char *str) | 文字列長 |
int Sleep(int time) | 0 |
char CreateSocket(char prot) | ソケット・ハンドル |
int StrLen(char *str) | 文字列長 |
char *StrCat(char *head, char*tail) | 結合された文字列 |
int StrCmp(char *str1, char *str2) |
|
char *StrCpy(char *dest, char *src) | dest |
char *StrChr(char *str, char scan) |
|
cahr *StrStr(char *str, char *scan) |
|
int SystemSleep(void) | 0 |
int Write(char socket, char *buf, int len) |
|
int Read(char socket, int timeout) |
|
int GetNetLine(char socket, char *buf, char size, char func) | |
| タイマ・ハンドル |
int GetTimerCount(char timer) |
|
- "PrXxxx"関数のいくつかは、可変引数に対応していて、それぞれの表示を空白デリミッタで区切って表示してくれます。 デリミッタは、ハードコーディングされているので、外部から変更することは出来ません。 う~ん、残念。
- "PrStr"関数は、返り値として表示した文字列の長さを返してくれます。 この機能は、私には、使途が思いつきません。
- ある情報から、"Read"関数は、8ビットの値を返しているように見えたのですが、16ビットの値を返していました。 このため、127バイトを超える長さのパケットも受信できます。
- "CreateTimer"関数は、引数として"0"を一つだけとる使い方ができます。 この場合、タイマの作成(確保?)のみ行います。
参考文献
Interface (インターフェース) 2008年 09月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/07/25
- メディア: 雑誌
I2CでLEDピカピカ (真)完全版 [ColdFire V2]
以前、MCF52233付録基板 - I2CでLEDピカピカ完全版という記事でフラグの扱いをマスターしたと思っていたのですが、「機械語に移植したら動かない」という声が上がりました。 原因は、HCS08由来のI2CモジュールとColdFire由来のI2Cモジュールの違いにあったようです。
SilentCは、遅いのが取り得
件の記事で作成したプログラムでは、インタラプトフラグをクリアするために、I2SR[IIF]ビットに1を書き込んでいました。 ところが、このシーケンスが誤っていたようで、フラグがクリアされていなかったようです。 調べてみると、仕様の違いが明らかになりました。
- MCF51QE128のIIFフラグは、"1"を書き込んでクリアする。
- MCF52233のIIFフラグは、"0"を書き込んでクリアする。
まったく、正反対の仕様です。 このため、フラグがクリアされる前に次に転送するデータを書き込んでしまい、正常にデータが転送されなかったということのようです。 前回のプログラムにフラグを表示させるステートメントを追加すると、その様子がわかります。
int *pqspar =0x4010006c; char *i2adr =0x40000300; char *i2fdr =0x40000304; char *i2cr =0x40000308; char *i2sr =0x4000030c; char *i2dr =0x40000310; main(){ int i; *pqspar =0x00A0; // PQSPAR[3:2]=10 (i2c) *i2fdr = 0x38; // (x640) *i2cr = 0x90; // See table write(0x03,0x00); // config as OUT #stop 0 i=0; for(;;){ if(Getc(0)=='q')break; Sleep(25); write(0x01,0xEF<<i); i=(i+1)&3; } } write(char com, char data){ while ((*i2sr)&0x20) SystemSleep(); // Wait for BUS idle *i2sr = 0x12; // Clear flags *i2cr |= 0x20; // START do { PrHexByte(*i2sr);PrStr(" "); *i2dr = 0x40; // WRITE for 0100000 while (!(*i2sr&0x02)); // Wait for IIF if (*i2sr&0x01) break; // Quit if no ACK *i2sr = 0x12; // Clear flags PrHexByte(*i2sr);PrStr(" "); *i2dr = com; // command while (!(*i2sr&0x02)); // Wait for IIF if (*i2sr&0x01) break; // Quit if no ACK *i2sr = 0x12; // Clear flags PrHexByte(*i2sr);PrStr("\r\n"); *i2dr = data; // data while (!(*i2sr&0x02)); // Wait for IIF } while (0); *i2cr &= 0xDF; // STOP }
OK run a2 a2 a6 a2 a2 a6 a6 a2 a6 a2 a2 a6 a2 a2 a6 a2 a2 a6
フラグがクリアされていれば、a0またはa4の値が並ぶはずです。
ここで、疑問が発生します。 問題のあるプログラムで、どうしてI2Cの通信が出来たのでしょうか? 答えは簡単。 SilentCの処理速度が遅いため、フラグを確認するまでにI2Cのパケットはすっかり送出されてしまっているため、データがぶつかることが無かったのです。 それでは、SilentCに匹敵するぐらい転送速度を遅くしたら、どうなるでしょうか。
write(char com, char data){ while ((*i2sr)&0x20) SystemSleep(); // Wait for BUS idle *i2sr = 0x12; // Clear flags *i2cr|=0x20;*i2dr=0x40;*i2dr=com;*i2dr=data;*i2cr&=0xDF; }
ボーレートを最低にして、処理速度を最大限にするように努力しましたが、このプログラムでも通信は正常に動いていました。 どうやら、SilentCを使う限りは、「フラグをクリアしなかったことによる弊害」は確認できないようです。
修正版I2CでLEDピカピカのプログラム
「もう、フラグを見る必要なんか無いんじゃないか。」とも思いましたが、気を取り直して、修正プログラムを作成しました。
int *pqspar =0x4010006c; char *i2adr =0x40000300; char *i2fdr =0x40000304; char *i2cr =0x40000308; char *i2sr =0x4000030c; char *i2dr =0x40000310; main(){ int i; *pqspar =0x00A0; // PQSPAR[3:2]=10 (i2c) *i2fdr = 0x38; // (x640) *i2cr = 0x90; // See table write(0x03,0x00); // config as OUT #stop 0 i=0; for(;;){ if(Getc(0)=='q')break; Sleep(25); write(0x01,0xEF<<i); i=(i+1)&3; } } write(char com, char data){ while ((*i2sr)&0x20) SystemSleep(); // Wait for BUS idle *i2sr = 0x00; // Clear flags *i2cr |= 0x20; // START do { PrHexByte(*i2sr);PrStr(" "); *i2dr = 0x40; // WRITE for 0100000 while (!(*i2sr&0x02)); // Wait for IIF if (*i2sr&0x01) break; // Quit if no ACK *i2sr = 0x00; // Clear flags PrHexByte(*i2sr);PrStr(" "); *i2dr = com; // command while (!(*i2sr&0x02)); // Wait for IIF if (*i2sr&0x01) break; // Quit if no ACK *i2sr = 0x00; // Clear flags PrHexByte(*i2sr);PrStr("\r\n"); *i2dr = data; // data while (!(*i2sr&0x02)); // Wait for IIF } while (0); *i2cr &= 0xDF; // STOP }
I2DRレジスタへの書き込みを行う前にI2SRレジスタを表示してくれる親切設計。 実際に使うときには、これらの表示ステートメントは削除してください。
OK run a0 a0 a4 a0 a0 a4 a4 a0 a4 a0 a0 a4 a0 a0 a4 a0 a0 a4 a4 a0 a4 a0 a0 a4 a0 a0 a4
ごらんのとおり、IIFフラグがクリアされているのが確認できました。
Interface誌のプログラムも
Interface 2008年9月号にも、I2Cを使って温度センサと通信を行うプログラムが掲載されています。 ところが、このプログラムでも「*sr|=2;」でフラグをクリアしたつもりになっています。 このプログラムも、SilentCの遅さに助けられているのですね。
参考文献
Interface (インターフェース) 2008年 09月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/07/25
- メディア: 雑誌
MCF52233に内蔵されているI2Cモジュールのフラグの操作は、HCS08シリーズのI2Cとは違っているので注意が必要です。 MC51QE128も、HCS08由来のモジュールを使っているので、MCF52233とは違っています。
HCS08 Unleashed: Designer's Guide to the Hcs08 Microcontrollers
- 作者: Fabio Pereira
- 出版社/メーカー: Booksurge Llc
- 発売日: 2007/11/13
- メディア: ペーパーバック
Sレコード生成プログラム [ColdFire V2]
どんなに時間が経過しても、モトローラの標準バイナリ・フォーマットは、「Sレコード」です。 ダンプを作成するなら、Sレコード生成プログラムは欠かせません。
Sレコードって、何だ
バイナリの情報をテキスト・ファイルに変換するためには、色々な方法があります。 最近では、BASE64というエンコード方法がメール添付ファイルなどで使われています。
マイコンのプログラムの場合、データももちろん重要なのですが、そのデータを配置するアドレスも情報として持っていなくてはなりません。 そのために、インテルが提唱したフォーマットを「HEX」と言い、モトローラが提唱したフォーマットを「Sレコード」と呼んでいます。
Sレコードのフォーマットをちょっとだけ
「Sレコード」は、一行完結のフォーマットで、各行の先頭が"S"という文字で始まっている事から、この名前で呼ばれています。 "S"の次には、"0"から"9"の文字が続き、その行が何をあらわしているのかを示します。
文字 "S" | レコードの種別を示す文字 | データ長を示す2文字の16進数 | 2文字の16進数単位で構成されるデータ本体 | チェックサム | 行末文字 |
多くの8ビットマイコンの場合、アドレス部分は16ビットです。 この場合、種別"1"を使います。 データ本体の最初の2バイトがアドレスを示します。
一方、ColdFireのように32ビットのアドレスを使用する場合には、種別"3"が使用されます。 この場合、データ本体の最初の4バイトがアドレスを示します。 今回のプログラムの場合には、種別"3"のレコードのみを生成します。
データ長は、データ長部分とデータ本体をあわせた長さをバイト単位で表したものです。
データ本体は、配置すべきアドレスに続いて配置するデータを並べます。
チェックサムは、データ長部分とデータ本体の和の1の補数になっています。 そのため、受信したデータを検証する場合には、データ長からチェックサムまでの和が$FFになることを確認します。
Sレコード生成プログラム
フォーマットを確認したところで、サクッとプログラムを書いてしまいます。
sd(long s, long len){ long i,n,nBytes=28; char cs,d; while(len>0){ n=(len>nBytes)?(nBytes):(len); PrStr("S3");PrHexByte(n+5);PrHex(s); cs=(n+5)+(s>>24)+(s>>16)+(s>>8)+s; for(i=0;i<n;i++){d=*(s+i);PrHexByte(d);cs+=d;} PrHexByte(~cs);PrStr("\r\n"); s+=n;len-=n; } }
この関数は、以前作成したダンプ・リスト生成関数と同じ"m"ファイルに入れておきます。 使用の際には、開始アドレスと長さを指定します。
m::sd(0x400,100) S32100000400ffffffffffffffff000000000000000000000000ffffffff46fc27007d S3210000041c2e7c20008000243c4000000006820000000123c24000000041f940109c S32100000438003f1410028200000001660000084ef9000200002c002e01203c20002c S3150000045400000680000002214e7b0c05203c0000b3
現状のプログラムでは、一行に表示するバイト数を28バイトにしてあります。 お好みの長さをnBytesに設定してご使用ください。
今日の問題
ところで、「Sレコード」を出して、何に使うのでしょうか?
参考文献
Interface (インターフェース) 2008年 09月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/07/25
- メディア: 雑誌
例外ベクタを調べた (5) [ColdFire V2]
RAMにも例外ベクタ・テーブルのような構造があることが判明しました。 このベクタ・テーブルが本当に使えるのか、実験してみます。
割り込みベクタを書き換える実験
もし、 RAM にある例外ベクタを CPU が使用しているのであれば、これらベクタを書き換えるだけで、割り込みを使用できる可能性があります。 また、 ROM にある例外ベクタを CPU が使用している場合でも、 VBR レジスタを変更すれば、 RAM にある例外ベクタ・テーブルを使用させることができるはずです。
実験は、普通に割り込みを受け入れさせる手順となんら変わりません。
どの割り込みを使おうか
割り込みを使うまでには、色々と準備が必要です。 まず、実験で使用する割り込みを決めます。 今回は、比較的処理が簡単なPIT1割り込みを使います。
PITについては、SilentCが使っていないモジュールを探せ(3)で調査だけしましたが、割り込みを発生する以外の仕事をしてくれそうになかったので、使ってみるまでには至りませんでした。 プリスケーラを256(28)分周に設定して、周期レジスタを29297カウントに設定すると、割り込み周期は約250ミリ秒になります。 その他の設定は、PIT0と同じにしておきました。
割り込み処理ルーチンを用意する
LNKLED端子をGPIO設定に変更しておき、PIT1の割り込み処理ルーチンでLNKLEDを反転させるとおなじみのLEDピカピカができるはずです。 そのためには、割り込み処理ルーチンを置く場所が必要です。
割り込み処理ルーチンは、前回調べた、例外ベクタ・テーブルの未使用部分である 0x20000300 からのアドレスに配置しました。 たぶん、この部分が使われることはないでしょう。
2F00 move.l d0,-(a7) ; save D0 3039 4016 0000 move.w PCSR1,d0 0080 0000 0004 ori.l #0x0004,d0 33C0 4016 0000 move.w d0,PCSR1 ; Clear PIF flag 1039 4010 0015 move.b PORTLD,d0 0A80 0000 0002 eori.l #0x02,d0 13C0 4010 0015 move.b d0,PORTLD ; Toggle LNKLED 201F move.l (a7)+,d0 ; restore D0 4E73 rte
ハンド・アセンブルは、何年ぶりだろう。 効率など微塵も考えていないプログラムですが、それにしてもコード効率が悪く見えるな。 中身は、PIT1のフラグをクリアし、LNKLED(PLD[1])を反転させているだけです。
さらに、割り込み処理ルーチンの場所を例外ベクタ・テーブルに書き込む必要があります。 PIT1の例外ベクタは、0x200001E0番地に書き込みます。
これらの一連の処理は、 write_pit_isr() という関数に記述しました。
PIT1割り込みを許可する
PIT1割り込みを許可するためには、二箇所のマスク・ビットを設定する必要があります。 ひとつは、PIT1モジュールのPCSR1[PIE]フラグです。 このフラグをセットすることで、割り込みが許可されます。
もうひとつは、INTC0モジュールのIMRH0[INT_MASK[56]]ビットです。 このビットをクリアすることで、割り込みが許可されます。
本当は、もう一箇所、INTC0モジュールのIMRL0[MASKALL]ビットをクリアする必要があるのですが、SilentCで他のモジュールの割り込みがすでに使用されているため、最初からクリアされています。
PIT1の割り込みレベルを設定する
8ビットマイコンの場合には、このぐらいで割り込みが使えるようになるのですが、MCF52233の場合には、もうひと手間必要です。 それは、PIT1割り込みのレベルを指定することです。
ColdFireの場合、多重割り込みを前提として作られているので、割り込み処理中に別の割り込みが発生する可能性があります。 このときに、新たに発生した割り込みを受け入れるかどうかを判断するのが割り込みレベルという概念です。 簡単に言うと、ある割り込み処理中は、処理中の割り込みよりも割り込みレベルの高い割り込みしか受け入れません。
今回の実験では、LEDピカピカという比較的軽い処理を行わせるので、レベル1割り込みとして処理させることにしました。 レベルを設定するレジスタは、0x40000C78番地のICR056です。 レベルの初期値は0です。 レベル0の割り込みは、CPUと同じレベルなので、このままでは割り込みは発生しません。
このレジスタには、複数の割り込み要求が発生した場合の優先順位を指定することも出来ます。 優先順位も最低の0としておきます。
PIT1割り込みでLEDピカピカ
全プログラムは、こんな風になりました。
char *portld=0x40100015; char *ddrld =0x4010002D; char *pldpar=0x40100075; int *pcsr1 =0x40160000; int *pmr1 =0x40160002; int *pcntr1=0x40160004; long *imrh0 =0x40000C08; char *icr056=0x40000C78; main() { // Prepare GPIO *portld = 0x00; // PORTLD[1:0]=0 *ddrld = 0x03; // DDRLD[1:0]=1 *pldpar = 0x00; // PLDPAR[1:0]=0 // Prepare INT write_pit_isr(); *imrh0 &= 0xFEFFFFFF; // enable PITI *icr056 = 0x08; // LEVEL=1 // Prepare PIT *pmr1 = 29297-1; // Period count *pcsr1 = 0x081F; // Start PIT1 #stop 0 for(;;){ if (Getc(0)=='q')break; PrNum(*pcntr1);PrStr(" ");Sleep(10); } *pcsr1 = 0x0000; // Stop PIT1 } write_pit_isr() { long *v = 0x200001E0; // vector #120 long *p = 0x20000300; // pit_isr *v = p; *p++=0x2F003039;*p++=0x40160000; *p++=0x00800000;*p++=0x000433C0; *p++=0x40160000;*p++=0x10394010; *p++=0x00150A80;*p++=0x00000002; *p++=0x13C04010;*p++=0x0015201F; *p++=0x4E730000; }
メインルーチンでは、'q'キーの入力を待ちながら、PIT1カウンタの値を延々と表示し続けるプログラムが走っています。 安全のため、プログラム終了時には、PIT1を停止させるようにしました。
プログラムを実行した結果、みごとにLNKLEDがピカピカを始めました。 どうやら、RAMに展開された例外ベクタが使用されている様子です。
参考文献
Interface (インターフェース) 2008年 09月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/07/25
- メディア: 雑誌
例外ベクタを調べた (4) [ColdFire V2]
例外ベクタ・テーブルは、ROM (0x00000000) または RAM (0x20000000) にしか存在し得ないということが分かっています。 さすがに、 32K バイトの RAM には、 1K バイトも必要なベクタ・テーブルは置かないだろうと思っていましたが。 あれっ? RAM にも例外ベクタ・テーブルみたいなものがありますよ。
CPUに直結したシステム例外
システム例外ベクタ・テーブルらしきものは、 0x2000000 から 0x200000FF までの 256 バイトに存在します。
20000000 20 00 80 00 00 00 04 18 ....... 20000008 00 01 15 f0 00 01 15 f0 ........ 20000010 00 01 15 f0 ff ff ff ff ........ 20000018 ff ff ff ff ff ff ff ff ........ 20000020 00 01 15 f0 00 01 15 f0 ........ 20000028 00 01 15 f0 00 01 15 f0 ........ 20000030 00 01 15 f0 ff ff ff ff ........ 20000038 00 01 15 f0 00 01 15 f0 ........ 20000040 ff ff ff ff ff ff ff ff ........ 20000048 ff ff ff ff ff ff ff ff ........ 20000050 ff ff ff ff ff ff ff ff ........ 20000058 ff ff ff ff ff ff ff ff ........ 20000060 ff ff ff ff 00 01 15 e0 ........ 20000068 00 01 15 e0 00 01 15 e0 ........ 20000070 00 01 15 e0 00 01 15 e0 ........ 20000078 00 01 15 e0 00 01 15 e0 ........ 20000080 00 01 15 f0 00 01 15 f0 ........ 20000088 00 01 15 f0 00 01 15 f0 ........ 20000090 00 01 15 f0 00 01 15 f0 ........ 20000098 00 01 15 f0 00 01 15 f0 ........ 200000a0 00 01 15 f0 00 01 15 f0 ........ 200000a8 00 01 15 f0 00 01 15 f0 ........ 200000b0 00 01 15 f0 00 01 15 f0 ........ 200000b8 00 01 15 f0 00 01 15 f0 ........ 200000c0 ff ff ff ff ff ff ff ff ........ 200000c8 ff ff ff ff ff ff ff ff ........ 200000d0 ff ff ff ff ff ff ff ff ........ 200000d8 ff ff ff ff ff ff ff ff ........ 200000e0 ff ff ff ff ff ff ff ff ........ 200000e8 ff ff ff ff ff ff ff ff ........ 200000f0 ff ff ff ff ff ff ff ff ........ 200000f8 00 1f e8 ** ** ** 00 00 ...***..
これは、完全に ROM (0x00000000 - 0x000000FF) の内容をコピーしてきたものです。 もし、 ROM ではなく、 RAM が例外ベクタ・テーブルとして使用されているのであれば、 SilentCから書き換える事だってできますね。
割り込みコントローラ0が発行する例外
割り込みコントローラ0に関連したベクタ・テーブルらしきものは、 0x2000100 から 0x200001FF までの 256 バイトに存在します。
20000100 00 01 15 e0 00 01 15 e0 ........ 20000108 00 01 15 e0 00 01 15 e0 ........ 20000110 00 01 15 e0 00 01 15 e0 ........ 20000118 00 01 15 e0 00 01 15 e0 ........ 20000120 00 01 15 e0 00 01 15 e0 ........ 20000128 00 01 15 e0 00 01 15 e0 ........ 20000130 00 01 15 e0 00 00 08 a4 ........ 20000138 00 01 15 e0 00 01 15 e0 ........ 20000140 00 01 15 e0 00 01 15 e0 ........ 20000148 00 01 15 e0 00 01 15 e0 ........ 20000150 00 01 15 e0 00 01 15 e0 ........ 20000158 00 01 15 e0 00 00 33 78 ......3x 20000160 00 00 33 b0 00 00 32 c0 ..3...2. 20000168 00 00 32 d0 00 00 31 e4 ..2...1. 20000170 00 00 32 e0 00 00 32 f0 ..2...2. 20000178 00 00 33 00 00 00 33 10 ..3...3. 20000180 00 00 33 38 00 00 33 48 ..38..3H 20000188 00 00 33 58 00 00 33 68 ..3X..3h 20000190 00 00 31 d4 00 01 15 e0 ..1..... 20000198 00 01 15 e0 00 01 15 e0 ........ 200001a0 00 01 15 e0 00 01 15 e0 ........ 200001a8 00 01 15 e0 00 01 15 e0 ........ 200001b0 00 01 15 e0 00 01 15 e0 ........ 200001b8 00 01 15 e0 00 01 15 e0 ........ 200001c0 00 01 15 e0 00 01 15 e0 ........ 200001c8 00 01 15 e0 00 01 15 e0 ........ 200001d0 00 01 15 e0 00 01 15 e0 ........ 200001d8 00 01 15 e0 00 00 18 78 .......x 200001e0 00 01 15 e0 00 01 15 e0 ........ 200001e8 00 01 15 e0 00 01 15 e0 ........ 200001f0 00 01 15 e0 00 01 15 e0 ........ 200001f8 00 01 15 e0 00 01 15 e0 ........
これも、完全に ROM (0x00000100 - 0x000001FF) の内容をコピーしてきたものです。
割り込みコントローラ1が発行する例外
割り込みコントローラ1に関連したベクタ・テーブルらしきものは、 0x2000200 から 0x200002FF までの 256 バイトに存在します。
20000200 00 01 15 e0 00 01 15 e0 ........ 20000208 00 01 15 e0 00 01 15 e0 ........ 20000210 00 01 15 e0 00 01 15 e0 ........ 20000218 00 01 15 e0 00 01 15 e0 ........ 20000220 00 01 15 e0 00 01 15 e0 ........ 20000228 00 01 15 e0 00 01 15 e0 ........ 20000230 00 01 15 e0 00 01 15 e0 ........ 20000238 00 01 15 e0 00 01 15 e0 ........ 20000240 00 01 15 e0 00 01 15 e0 ........ 20000248 00 01 15 e0 00 01 15 e0 ........ 20000250 00 01 15 e0 00 01 15 e0 ........ 20000258 00 01 15 e0 00 01 15 e0 ........ 20000260 00 01 15 e0 00 01 15 e0 ........ 20000268 00 01 15 e0 00 01 15 e0 ........ 20000270 00 01 15 e0 00 01 15 e0 ........ 20000278 00 01 15 e0 00 01 15 e0 ........ 20000280 00 01 15 e0 00 01 15 e0 ........ 20000288 00 01 15 e0 00 01 15 e0 ........ 20000290 00 01 15 e0 00 01 15 e0 ........ 20000298 00 01 15 e0 00 01 15 e0 ........ 200002a0 00 01 15 e0 00 01 15 e0 ........ 200002a8 00 01 15 e0 00 01 15 e0 ........ 200002b0 00 01 15 e0 00 01 15 e0 ........ 200002b8 00 01 15 e0 00 01 15 e0 ........ 200002c0 00 01 15 e0 00 01 15 e0 ........ 200002c8 00 01 15 e0 00 01 15 e0 ........ 200002d0 00 01 15 e0 00 01 15 e0 ........ 200002d8 00 01 15 e0 00 01 15 e0 ........ 200002e0 00 01 15 e0 00 01 15 e0 ........ 200002e8 00 01 15 e0 00 01 15 e0 ........ 200002f0 00 01 15 e0 00 01 15 e0 ........ 200002f8 00 01 15 e0 00 01 15 e0 ........
みごとに全てのベクタが「その他の例外処理ルーチン」を使用しています。 この部分は、 ROM (0x00000200 - 0x000002FF) の内容とは違っていますね。
ベクタだけが割り当てられた例外
ColdFire は、全部で 256 の例外ベクタを持ちます。 最後の64個のベクタは、ベクタ・テーブルとして確保はされていますが、MCF52233では、全く使われていないベクタです。
20000300 00 01 15 e0 00 01 15 e0 ........ 20000308 00 01 15 e0 00 01 15 e0 ........ 20000310 00 01 15 e0 00 01 15 e0 ........ 20000318 00 01 15 e0 00 01 15 e0 ........ 20000320 00 01 15 e0 00 01 15 e0 ........ 20000328 00 01 15 e0 00 01 15 e0 ........ 20000330 00 01 15 e0 00 01 15 e0 ........ 20000338 00 01 15 e0 00 01 15 e0 ........ 20000340 00 01 15 e0 00 01 15 e0 ........ 20000348 00 01 15 e0 00 01 15 e0 ........ 20000350 00 01 15 e0 00 01 15 e0 ........ 20000358 00 01 15 e0 00 01 15 e0 ........ 20000360 00 01 15 e0 00 01 15 e0 ........ 20000368 00 01 15 e0 00 01 15 e0 ........ 20000370 00 01 15 e0 00 01 15 e0 ........ 20000378 00 01 15 e0 00 01 15 e0 ........ 20000380 00 01 15 e0 00 01 15 e0 ........ 20000388 00 01 15 e0 00 01 15 e0 ........ 20000390 00 01 15 e0 00 01 15 e0 ........ 20000398 00 01 15 e0 00 01 15 e0 ........ 200003a0 00 01 15 e0 00 01 15 e0 ........ 200003a8 00 01 15 e0 00 01 15 e0 ........ 200003b0 00 01 15 e0 00 01 15 e0 ........ 200003b8 00 01 15 e0 00 01 15 e0 ........ 200003c0 00 01 15 e0 00 01 15 e0 ........ 200003c8 00 01 15 e0 00 01 15 e0 ........ 200003d0 00 01 15 e0 00 01 15 e0 ........ 200003d8 00 01 15 e0 00 01 15 e0 ........ 200003e0 00 01 15 e0 00 01 15 e0 ........ 200003e8 00 01 15 e0 00 01 15 e0 ........ 200003f0 00 01 15 e0 00 01 15 e0 ........ 200003f8 00 01 15 e0 00 01 15 e0 ........
この部分も全てのベクタが「その他の例外処理ルーチン」を使用しています。
RAMにも、例外ベクタ・テーブルのような構造があることが分かりましたが、これが使われているのかどうかは定かではありません。 ROMの例外ベクタ・テーブルを書き換えるのは、大変ですが、RAMにあれば簡単に書き換えられます。 いっちょ、実験してみるか。
参考文献
Interface (インターフェース) 2008年 09月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/07/25
- メディア: 雑誌
例外ベクタを調べた (3) [ColdFire V2]
例外ベクタを調べる三回目は、残りの128個の例外について調べます。
割り込みコントローラ1が発行する例外
MCF52233の二つの割り込みコントローラのうちINTC1は、ベクタ番号128から191までの割り込みを受け付けます。 INTC1が扱う例外は、 FLEXCAN と EPORT なので、この部分は未使用であることを期待していたのですが、なにやらアドレスらしきものがぎっしりと詰まっています。
00000200 00 00 1c c4 00 00 0b c4 ........ 00000208 00 00 0c dc 00 00 1d 58 .......X 00000210 00 00 19 84 00 00 1f 50 .......P 00000218 00 00 1e 80 00 00 1f 2c ......., 00000220 00 00 0e cc 00 00 0e 30 .......0 00000228 00 00 0f 9c 00 00 0d f8 ........ 00000230 00 00 0f 6c 00 00 0e ec ...l.... 00000238 00 00 0d 74 00 00 bf 08 ...t.... 00000240 00 00 7e cc 00 00 0a 00 ..~..... 00000248 00 00 0a 2c 00 00 0a a4 ...,.... 00000250 00 00 0a cc 00 00 0b 2c ......., 00000258 00 00 2f 2c 00 00 2d 34 ../,..-4 00000260 00 00 24 04 00 00 25 24 ..$...%$ 00000268 00 00 26 04 00 00 26 34 ..&...&4 00000270 00 00 26 d4 00 00 28 5c ..&...(\ 00000278 00 00 29 78 00 00 29 cc ..)x..). 00000280 00 00 2a 54 00 00 2a cc ..*T..*. 00000288 00 00 22 b0 00 00 48 48 .."...HH 00000290 00 00 49 80 00 00 5c e8 ..I...\. 00000298 00 00 5f ac 00 00 49 20 .._...I 000002a0 00 00 5d f4 00 00 5e e8 ..]...^. 000002a8 00 00 4f 1c 00 00 4e ec ..O...N. 000002b0 00 00 4b b8 00 00 4d 2c ..K...M, 000002b8 00 00 4c 20 00 00 4c bc ..L ..L. 000002c0 00 00 4c f4 00 00 60 c0 ..L...`. 000002c8 00 00 5c 7c 00 00 13 38 ..\|...8 000002d0 00 00 12 f4 00 00 13 e4 ........ 000002d8 00 00 16 dc 00 00 17 a4 ........ 000002e0 00 00 16 14 00 00 13 90 ........ 000002e8 00 01 15 e0 00 01 15 e0 ........ 000002f0 00 01 15 e0 00 01 15 e0 ........ 000002f8 00 01 15 e0 00 01 15 e0 ........
実は、割り込みコントローラを操作して、任意の例外を発生させる方法が無いわけではありません。 INTC1モジュールの INTFRCH1 と INTFRCH0 という二つのレジスタをセットすると該当する割り込みを発生させることが出来ます。 しかしながら、このレジスタを使ってもベクタ番号128の割り込みを発生させることは出来ないので、0x00000200番地にあるベクタは使用できないと思われます。
この仕掛けをシステム・コール代わりに使ったのでしょうか? 今のところは、想像しかできません。
ベクタ・テーブルだけの例外
0x00000300からの256バイトには、ベクタ番号192から255までに相当するベクタ・テーブルが置かれることになっていますが、MCF52233の場合には、この範囲の例外を発行するモジュールは存在しません。
00000300 00 01 15 e0 00 01 15 e0 ........ 00000308 00 01 15 e0 00 01 15 e0 ........ 00000310 00 01 15 e0 00 01 15 e0 ........ 00000318 00 01 15 e0 00 01 15 e0 ........ 00000320 00 01 15 e0 00 01 15 e0 ........ 00000328 00 01 15 e0 00 01 15 e0 ........ 00000330 00 01 15 e0 00 01 15 e0 ........ 00000338 00 01 15 e0 00 01 15 e0 ........ 00000340 00 01 15 e0 00 01 15 e0 ........ 00000348 00 01 15 e0 00 01 15 e0 ........ 00000350 00 01 15 e0 00 01 15 e0 ........ 00000358 00 01 15 e0 00 01 15 e0 ........ 00000360 00 01 15 e0 00 01 15 e0 ........ 00000368 00 01 15 e0 00 01 15 e0 ........ 00000370 00 01 15 e0 00 01 15 e0 ........ 00000378 00 01 15 e0 00 01 15 e0 ........ 00000380 00 01 15 e0 00 01 15 e0 ........ 00000388 00 01 15 e0 00 01 15 e0 ........ 00000390 00 01 15 e0 00 01 15 e0 ........ 00000398 00 01 15 e0 00 01 15 e0 ........ 000003a0 00 01 15 e0 00 01 15 e0 ........ 000003a8 00 01 15 e0 00 01 15 e0 ........ 000003b0 00 01 15 e0 00 01 15 e0 ........ 000003b8 00 01 15 e0 00 01 15 e0 ........ 000003c0 00 01 15 e0 00 01 15 e0 ........ 000003c8 00 01 15 e0 00 01 15 e0 ........ 000003d0 00 01 15 e0 00 01 15 e0 ........ 000003d8 00 01 15 e0 00 01 15 e0 ........ 000003e0 00 01 15 e0 00 01 15 e0 ........ 000003e8 00 01 15 e0 00 01 15 e0 ........ 000003f0 00 01 15 e0 00 01 15 e0 ........ 000003f8 00 01 15 e0 00 01 15 e0 ........
すべて、「その他の例外処理ルーチン」アドレスで埋め尽くされています。
参考文献
Interface (インターフェース) 2008年 09月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/07/25
- メディア: 雑誌
例外ベクタを調べた (2) [ColdFire V2]
例外ベクタを調べる二回目は、割り込みコントローラ0が発行する例外について調べます。
割り込みコントローラ0が発行する例外
MCF52233の二つの割り込みコントローラのうちINTC0は、ベクタ番号64から127までの割り込みを受け付けます。
ベクタ番号 | ベクタ・アドレス | ベクタ | 用途 |
---|---|---|---|
64 | 0x100 | 0x000115E0 | 未使用 |
65 | 0x104 | 0x000115E0 | エッジ・ポート1 |
66 | 0x108 | 0x000115E0 | エッジ・ポート2 |
67 | 0x10C | 0x000115E0 | エッジ・ポート3 |
68 | 0x110 | 0x000115E0 | エッジ・ポート4 |
69 | 0x114 | 0x000115E0 | エッジ・ポート5 |
70 | 0x118 | 0x000115E0 | エッジ・ポート6 |
71 | 0x11C | 0x000115E0 | エッジ・ポート7 |
72 | 0x120 | 0x000115E0 | ウォッチ・ドッグ |
73 | 0x124 | 0x000115E0 | DMA0 |
74 | 0x128 | 0x000115E0 | DMA1 |
75 | 0x12C | 0x000115E0 | DMA2 |
76 | 0x130 | 0x000115E0 | DMA3 |
77 | 0x134 | 0x000008A4 | UART0 |
78 | 0x138 | 0x000115E0 | UART1 |
79 | 0x13C | 0x000115E0 | UART2 |
80 | 0x140 | 0x000115E0 | 未使用 |
81 | 0x144 | 0x000115E0 | I2C |
82 | 0x148 | 0x000115E0 | QSPI |
83 | 0x14C | 0x000115E0 | DMA Timer 0 |
84 | 0x150 | 0x000115E0 | DMA Timer 1 |
85 | 0x154 | 0x000115E0 | DMA Timer 2 |
86 | 0x158 | 0x000115E0 | DMA Timer 3 |
87 | 0x15C | 0x00003378 | FEC TX frame |
88 | 0x160 | 0x000033B0 | FEC TX buffer |
89 | 0x164 | 0x000033C0 | FEC TX underrun |
90 | 0x168 | 0x000032D0 | FEC Collision retry limit |
91 | 0x16C | 0x000031E4 | FEC RX frame |
92 | 0x170 | 0x000032E0 | FEC RX buffer |
93 | 0x174 | 0x000032F0 | FEC MII |
94 | 0x178 | 0x00003300 | FEC Late Collision |
95 | 0x17C | 0x00003310 | FEC Heartbeat error |
96 | 0x180 | 0x00003338 | FEC Graceful stop complete |
97 | 0x184 | 0x00003348 | FEC Ethernet bus error |
98 | 0x188 | 0x00003358 | FEC Babbling TX error |
99 | 0x18C | 0x00003368 | FEC Babbling RX error |
100 | 0x190 | 0x000031D4 | EPHY |
101 | 0x194 | 0x000115E0 | 未使用 |
102 | 0x198 | 0x000115E0 | 未使用 |
103 | 0x19C | 0x000115E0 | 未使用 |
104 | 0x1A0 | 0x000115E0 | 未使用 |
105 | 0x1A4 | 0x000115E0 | GPT オーバフロー |
106 | 0x1A8 | 0x000115E0 | GPT PAC入力 |
107 | 0x1AC | 0x000115E0 | GPT PAC オーバフロー |
108 | 0x1B0 | 0x000115E0 | GPT チャネル0 |
109 | 0x1B4 | 0x000115E0 | GPT チャネル1 |
110 | 0x1B8 | 0x000115E0 | GPT チャネル2 |
111 | 0x1BC | 0x000115E0 | GPT チャネル3 |
112 | 0x1C0 | 0x000115E0 | 低電圧検出 |
113 | 0x1C4 | 0x000115E0 | A/Dコンバータ A |
114 | 0x1C8 | 0x000115E0 | A/Dコンバータ B |
115 | 0x1CC | 0x000115E0 | A/Dコンバータ割り込み |
116 | 0x1D0 | 0x000115E0 | PWM |
117 | 0x1D4 | 0x000115E0 | RNGA |
118 | 0x1D8 | 0x000115E0 | 未使用 |
119 | 0x1DC | 0x00001878 | PIT0 |
120 | 0x1E0 | 0x000115E0 | PIT1 |
121 | 0x1E4 | 0x000115E0 | 未使用 |
122 | 0x1E8 | 0x000115E0 | 未使用 |
123 | 0x1EC | 0x000115E0 | Flash buffer empty |
124 | 0x1F0 | 0x000115E0 | Flash command complete |
125 | 0x1F4 | 0x000115E0 | Flash Protection violation |
126 | 0x1F8 | 0x000115E0 | Flash Access error |
127 | 0x1FC | 0x000115E0 | RTC |
こうして見ると、ほとんどが「その他の例外処理ルーチン」である0x000115E0をベクタとして持っています。 使用されているのは、Etherポートの全てとUART0とPIT0です。 これまで調べてきて分かったように、PIT0がオペレーティング・システムの10ミリ秒タイマに使用されており、EthernetとUART0がSilentCとのインターフェースに使用されています。
これらのベクタは、ROMに書き込まれているため、そのままでは使えないと思います。 もし、「その他の例外処理ルーチン」が、割り込み要因によって分岐するような仕掛けを持っていれば、その仕組みを使うことも出来ます。 さて、本当にそんな仕掛けが入っているんだろうか?
参考文献
Interface (インターフェース) 2008年 09月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/07/25
- メディア: 雑誌