SSブログ

HTML文書にGIFをたくさん埋め込んでみた - Firefox の奥の手 [ColdFire V2]このエントリーを含むはてなブックマーク#

1990557

付録基板の http サーバに Firefox で接続した時の問題は、同時に張るコネクション数が多すぎる為であるらしい事が分かってきました。 だったら、 Firefox に同時コネクション数を減らすように指示してやろう。

about:config というページの存在

Firefoxには、設定を変えるための"about:config"というページがあります。 アドレス欄に"about:config"と打ち込むと、この設定ページが開きます。 最近は、「動作保証外になります!」という警告が出てくるのね。 Firefoxに「動作保証」なんてあったんだっけ。

設定項目が山のように並んでいるので、必要な項目だけフィルタリングすることが出来ます。 ここでは、フィルタ欄に".http."と入力して必要な項目を出します。 それぞれの項目をダブル・クリックするか、右クリックでプルダウン・メニューを出して値を変更します。 付録基板のhttpサーバのご機嫌をとるために設定した項目は、以下の三つです。

設定名備考
network.http.max-connections-per-server3 サーバあたりの最大コネクション数。 ColdFireは、最大三つしかコネクションを受け付けないらしい事が実験的にわかってきました。 Firefox 3.0.3のデフォルトは、なんと"15"になっていたので、付録基板がアップアップしていたのもうなずけます。
network.http.max-persistent-connections-per-server3 サーバあたりの最大永続コネクション数。 どういうコネクションを意味するのか分かりませんが、デフォルトの"6"が大きすぎるのは明らかだと思います。
network.http.version1.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秒と順調に進んでいます。

通信のまとめ

packets3.png

以上のように二箇所の再送処理はありましたが、全てのコネクションが2秒あまりで順調に終了しています。 しかも、取り損なった"ACK"も残っていません。 Firefoxで付録基板のhttpサーバと接続するときには、これぐらいの設定を行えば、実用的な速度でWEBページを表示することが出来そうです。

参考文献

Interface (インターフェース) 2008年 09月号 [雑誌]

Interface (インターフェース) 2008年 09月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/07/25
  • メディア: 雑誌

HTML文書にGIFをたくさん埋め込んでみた - Internet Explorerの場合 [ColdFire V2]このエントリーを含むはてなブックマーク#

2047506

前回の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"を打ち続けます。

通信のまとめ

packets2.png

通信の様子を図にしてみました。 詰まっているので判断しづらいのですが、同時に存在するコネクションの数が二つに制限されているように見えます。 どうやら、コネクションの数が少なければ、httpサーバとの通信はうまくいくようです。 あるいは、Internet Explorer にチューニングしてあるのだろうか。

参考文献

Interface (インターフェース) 2008年 09月号 [雑誌]

Interface (インターフェース) 2008年 09月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/07/25
  • メディア: 雑誌

HTML文書にGIFをたくさん埋め込んでみた - Firefoxの場合 [ColdFire V2]このエントリーを含むはてなブックマーク#

1990557

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種類、用意しました。

Fu0.gif Fu1.gif Gk1.gif Gn0.gif Gn1.gif Kn1.gif Ry0.gif

表示できたかな?

WS000165.png

ブラウザで表示させましたが、後手の「歩」と先手の「銀」が表示されませんでした。 しかも、ここまで表示するのに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"に反応した順に表にしてみました。

ポートファイルコネクション
1147HTML#2 - #66
1151Ke1.gif#8 - #26
1153Kn1.gif#14 - #35
1158Fu0.gif#32 - #58
1160Ry0.gif#40 - #65
1163Gn0.gif#68 - #77
1161Fu1.gif#78 -
1156Gk1.gif#80 -
1154Gn1.gif#79 -

packets1.png

図も描いてみました。 緑色の部分が実際にデータを送受信した部分です。 ブラウザの再送間隔が長いために全体の通信時間が長くなってしまったものと思われます。

この表から、httpサーバが同時に張ることができるのは、最大三つのコネクションらしいことがわかります。 また、最後の三つのコネクションについては、コネクションが確実に終了していません。 どのGIFファイルもデータそのものは送られてきているのですが、コネクションの終了が確実ではないために破損したイメージとして表示されるものと思われます。

次回はIEでの通信をパケット・モニタにかけます。

参考文献

Interface (インターフェース) 2008年 09月号 [雑誌]

Interface (インターフェース) 2008年 09月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/07/25
  • メディア: 雑誌

付録基板のhttpサーバをダウングレードしてみた [ColdFire V2]このエントリーを含むはてなブックマーク#

2047506

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"を確実に返しています。 そのため、パケットの送受信は、ここで終了します。

本日の考察

  1. httpサーバをHTTP1.0にダウン・グレードすると、ブラウザは同時に複数の通信を要求する振る舞いはしない。
  2. ただし、データ転送が終了した後でもコネクションは張られたままなので、複数コネクションを行っているようにも見える。
  3. ブラウザが"FIN"を発行するタイミングが早いので、ColdFireは、"ACK"で応える事が出来る。

GIFファイルの数をもっと増やしたらどうなるんでしょうね。

参考文献

Interface (インターフェース) 2008年 09月号 [雑誌]

Interface (インターフェース) 2008年 09月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/07/25
  • メディア: 雑誌

ColdFireマイコンがネットワークにつながらない!? [ColdFire V2]このエントリーを含むはてなブックマーク#

2047506

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月号 [雑誌]

Interface (インターフェース) 2008年 09月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/07/25
  • メディア: 雑誌

HTML文書にGIFを埋め込んでみた [ColdFire V2]このエントリーを含むはてなブックマーク#

1990557

付録基板の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ファイルは、これだ

GIFファイルとして用意したのは、W.gifB.gifです。

表示できたかな?

WS000164.png

ブラウザで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は、返答しません。 やっぱり、おかしいな。

本日の考察

  1. ブラウザが、複数のGETリクエストを同一のポートから出した、つまりコネクションを使い回しした場合、ColdFireは、二回目のリクエストに受信確認を出した後すぐにコネクションを切断してしまう。
  2. ColdFireのhttpサーバは、ブラウザからの要求に対して少なくとも二つコネクションを張ることが出来る。
  3. 複数のコネクションが張られたとき、コネクションの切断に必要なhttpサーバからのACKをColdFireは返さない。

TCP/IPの仕様として、どんな振る舞いがふさわしいのか理解していないので、ブラウザとColdFireのhttpサーバのどちらに問題があるのか、私には判断出来ません。

参考文献

Interface (インターフェース) 2008年 09月号 [雑誌]

Interface (インターフェース) 2008年 09月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/07/25
  • メディア: 雑誌

HTTPサーバのCGI機能を極める [ColdFire V2]このエントリーを含むはてなブックマーク#

1990557

付録基板の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文字で打ち切られてしまいました。 内部処理で準備されたバッファの長さの限界ということでしょうか。 おまけに、コンソールにゴミが出力されて、時には暴走してしまいます。 何か、壊しちゃったみたいですね。

本日の考察

  1. HTTPサーバのCGI機能は、元の文書の該当箇所を置き換える機能である。
  2. CGI機能で長い文字列を出したいときには、元の文書で場所を確保しておかなくてはならない。
  3. 置き換えられる文字数は、81文字が限界で、これ以上長くすると暴走の危険がある。ただし、81文字であれば絶対に安全かという検証はしていない。

どうやら、この置き換えの作業をしているのが、"ReplaceCgi"という関数のようです。 このCGI機能で表を作成するのは、難しそうだな。

参考文献

Interface (インターフェース) 2008年 09月号 [雑誌]

Interface (インターフェース) 2008年 09月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/07/25
  • メディア: 雑誌

SilentCの関数一覧表 (3) [ColdFire V2]このエントリーを含むはてなブックマーク#

1990557

SilentCの関数一覧表を作成しました。 コメント!--も合わせてお読みください。

SilentC 関数一覧表 (3)

SilentC 関数一覧表 (3)
関数返り値
long Atoi(char *buf)
char Bind(char socket, int port, char maxsoc)
  • 0 - エラー
  • 1 - 正常
char Accept(char socket, int timeout)
  • 正 - ソケット番号
  • -1 - 無効ソケット番号
  • -2 - 時間切れ
  • -3 -
int GetSenderPort(char socket)
  • 0 - エラー
  • 非0 - ポート番号
long GetSenderIP(char socket)
  • 0 - エラー
  • 非0 - IPアドレス
int SendTo(char socket, long ip, int port, char *buf, int len)
int RecvFrom(char socket, int timeout)
  • 正 - 受信データ長
  • -1 - 無効ソケット番号
  • -2 - 時間切れ
int DoCgi(char *ptr)0
char *ReplaceCgi(long p4, int p10)
int GetDefMtu(char socket, int size)
  • 正 - MTU値
  • -1 - エラー
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月号 [雑誌]

Interface (インターフェース) 2008年 09月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/07/25
  • メディア: 雑誌

SilentCの知られざる世界 (1) [ColdFire V2]このエントリーを含むはてなブックマーク#

1990557

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月号 [雑誌]

Interface (インターフェース) 2008年 09月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/07/25
  • メディア: 雑誌

SilentCの関数一覧表 (2) [ColdFire V2]このエントリーを含むはてなブックマーク#

1990557

SilentCの関数一覧表を作成しました。 コメント!--も合わせてお読みください。

SilentC 関数一覧表 (2)

SilentC 関数一覧表 (2)
関数返り値
int FormatFilesys(int key)0
int DefragFilesys(int key)0
long GetFilnalPos(void)
char CreateFile(char *name)
  • 0 -
  • 1 -
  • 2 -
  • 3 -
  • 4 -
  • 5 -
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)
  • 正 - 受信バイト数
  • -1 - Ctrl+Cを検出
char Getc(long wait)
  • 非0 - 受信文字
  • 0 - 受信文字無し

"CreateFile"関数が返してくる値は、0から5まで用意されているが、詳細は未解明である。

"OpenFile"関数が返してくるファイル・ハンドルは、ファイル構造体のアドレスである。 このため、"int"ではなく"long"でなくてはならない。 同様に"CloseFile"関数などで使用されるファイル・ハンドルも"long"である。

"FileGets"関数の引数sizeは、"long"で与えられるが、内部では、符号無し8ビットとして使われている。 しかも、実際に読み込んだ文字数は、16ビットで数えられていて、返り値に使用されている。

"SciPutc"関数の引数"char ch"は、第二引数で与えられているように見える。 実際に第二引数が表示されるのを確認した。

"SciGets"関数の引数maxは、"long"で与えられるが、内部では符号無し8ビットとして使われている。

参考文献

Interface (インターフェース) 2008年 09月号 [雑誌]

Interface (インターフェース) 2008年 09月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/07/25
  • メディア: 雑誌

TCP受信ルーチンにSystemSleepを散りばめる [ColdFire V2]このエントリーを含むはてなブックマーク#

2047506

"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

これは、問題なさそうです。

本日の考察

以上の実験から、以下の事柄が判明しました。

  1. SilentCは、受信したセグメントの処理が終わらないうちに、早々に受信確認を送っているように見える。結果として、さっさと次のセグメントが送られてきてしまい、受信に失敗しているので、自分で自分の首を絞めているのではないか。
  2. PCは、再送が必要になるような信頼性の低い通信路であることを認識すべきなのに、手加減せずにパケットを送りつけてくる。これは、クライアントが常に主張している1454バイトのウィンドウ・サイズと関連するのかもしれない。

参考文献

Interface (インターフェース) 2008年 09月号 [雑誌]

Interface (インターフェース) 2008年 09月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/07/25
  • メディア: 雑誌
ネットワークマガジン 2004年2月号
特集1 徹底図解 はじめての「プロトコル」

「過去記事PDF」が入っている付録CD-ROMを引っ張り出してきました。


TCP通信の監視にパケット・モニタを使ってみよう [ColdFire V2]このエントリーを含むはてなブックマーク#

2047506

付録基板との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で受信確認します。

このように、サーバが再送信を行えば通信が成り立ち、クライアントはすべての受信することができます。

本日の考察

以上の結果から、以下の事柄が判明、推測されました。

  1. SilentCから送信されるパケットのウィンドウサイズは、いつも1454バイトである。
  2. 受信確認(ACK)が届いていないにもかかわらず、PCからセグメントが再送されない場合がある。
  3. SilentCが送信するべき受信確認パケットが「しばしば」届かない。
  4. 再送信セグメントに対するSilentCの応答が不適切な場合がある。
  5. パケットひとつひとつに対してハンド・シェイクを行えば、欠損無く通信ができるらしい。

参考文献

Interface (インターフェース) 2008年 09月号 [雑誌]

Interface (インターフェース) 2008年 09月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/07/25
  • メディア: 雑誌

Read関数の最大受信サイズを調べる [ColdFire V2]このエントリーを含むはてなブックマーク#

2047506

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;

/**
 * This TcpEchoServer 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 a TcpEchoServer 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 in byte[]
   */
  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

これは、サーバとクライアントが共にデータを送ろうとした結果、ハングしたものと思われます。

本日の結論

  1. "Read"関数には、127バイトを超えるデータを受信する能力がある。
  2. しかし、SilentCで大きなデータを受信するのは苦しい。バッファサイズの536バイトを上限としてボチボチ送ったほうが良さそうだ。

参考文献

Interface (インターフェース) 2008年 09月号 [雑誌]

Interface (インターフェース) 2008年 09月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/07/25
  • メディア: 雑誌
TCP/IP解説書のお勧め募集中。

SilentCの関数一覧表 (1) [ColdFire V2]このエントリーを含むはてなブックマーク#

1990557

SilentCの関数一覧表を作成しました。

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)
  • 正 - str1 > str2
  • 零 - str1 = str2
  • 負 - str1 < str2
char *StrCpy(char *dest, char *src)dest
char *StrChr(char *str, char scan)
  • 0 - 発見されず
  • 非0 - 発見位置
cahr *StrStr(char *str, char *scan)
  • 0 - 発見されず
  • 非0 - 発見位置
int SystemSleep(void)0
int Write(char socket, char *buf, int len)
  • 0以上 - 送信バイト数
  • -1 - エラー
  • -3 - エラー
int Read(char socket, int timeout)
  • 0以上 - 受信バイト数
  • -1 - エラー
  • -2 - タイムアウト
  • -3 - ???
int GetNetLine(char socket, char *buf, char size, char func)
  • char CreateTimer(char timer)
  • char CreateTimer(char timer, int interval, char *func)
タイマ・ハンドル
int GetTimerCount(char timer)
  • 0 - timer=0
  • カウンタ値 - timer!=0
  • "PrXxxx"関数のいくつかは、可変引数に対応していて、それぞれの表示を空白デリミッタで区切って表示してくれます。 デリミッタは、ハードコーディングされているので、外部から変更することは出来ません。 う~ん、残念。
  • "PrStr"関数は、返り値として表示した文字列の長さを返してくれます。 この機能は、私には、使途が思いつきません。
  • ある情報から、"Read"関数は、8ビットの値を返しているように見えたのですが、16ビットの値を返していました。 このため、127バイトを超える長さのパケットも受信できます。
  • "CreateTimer"関数は、引数として"0"を一つだけとる使い方ができます。 この場合、タイマの作成(確保?)のみ行います。

参考文献

Interface (インターフェース) 2008年 09月号 [雑誌]

Interface (インターフェース) 2008年 09月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/07/25
  • メディア: 雑誌

I2CでLEDピカピカ (真)完全版 [ColdFire V2]このエントリーを含むはてなブックマーク#

2073158

以前、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月号 [雑誌]

Interface (インターフェース) 2008年 09月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/07/25
  • メディア: 雑誌

MCF52233に内蔵されているI2Cモジュールのフラグの操作は、HCS08シリーズのI2Cとは違っているので注意が必要です。 MC51QE128も、HCS08由来のモジュールを使っているので、MCF52233とは違っています。

HCS08 Unleashed: Designer's Guide to the Hcs08 Microcontrollers

HCS08 Unleashed: Designer's Guide to the Hcs08 Microcontrollers

  • 作者: Fabio Pereira
  • 出版社/メーカー: Booksurge Llc
  • 発売日: 2007/11/13
  • メディア: ペーパーバック

Sレコード生成プログラム [ColdFire V2]このエントリーを含むはてなブックマーク#

1990557

どんなに時間が経過しても、モトローラの標準バイナリ・フォーマットは、「Sレコード」です。 ダンプを作成するなら、Sレコード生成プログラムは欠かせません。

Sレコードって、何だ

バイナリの情報をテキスト・ファイルに変換するためには、色々な方法があります。 最近では、BASE64というエンコード方法がメール添付ファイルなどで使われています。

マイコンのプログラムの場合、データももちろん重要なのですが、そのデータを配置するアドレスも情報として持っていなくてはなりません。 そのために、インテルが提唱したフォーマットを「HEX」と言い、モトローラが提唱したフォーマットを「Sレコード」と呼んでいます。

Sレコードのフォーマットをちょっとだけ

「Sレコード」は、一行完結のフォーマットで、各行の先頭が"S"という文字で始まっている事から、この名前で呼ばれています。 "S"の次には、"0"から"9"の文字が続き、その行が何をあらわしているのかを示します。

Sレコードのフォーマット
文字 "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月号 [雑誌]

Interface (インターフェース) 2008年 09月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/07/25
  • メディア: 雑誌

例外ベクタを調べた (5) [ColdFire V2]このエントリーを含むはてなブックマーク#

1990557

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月号 [雑誌]

Interface (インターフェース) 2008年 09月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/07/25
  • メディア: 雑誌

例外ベクタを調べた (4) [ColdFire V2]このエントリーを含むはてなブックマーク#

1990557

例外ベクタ・テーブルは、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月号 [雑誌]

Interface (インターフェース) 2008年 09月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/07/25
  • メディア: 雑誌

例外ベクタを調べた (3) [ColdFire V2]このエントリーを含むはてなブックマーク#

1990557

例外ベクタを調べる三回目は、残りの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モジュールの INTFRCH1INTFRCH0 という二つのレジスタをセットすると該当する割り込みを発生させることが出来ます。 しかしながら、このレジスタを使ってもベクタ番号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月号 [雑誌]

Interface (インターフェース) 2008年 09月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/07/25
  • メディア: 雑誌

例外ベクタを調べた (2) [ColdFire V2]このエントリーを含むはてなブックマーク#

1990557

例外ベクタを調べる二回目は、割り込みコントローラ0が発行する例外について調べます。

割り込みコントローラ0が発行する例外

MCF52233の二つの割り込みコントローラのうちINTC0は、ベクタ番号64から127までの割り込みを受け付けます。

例外ベクタ 64-127
ベクタ番号ベクタ・アドレスベクタ用途
640x1000x000115E0未使用
650x1040x000115E0エッジ・ポート1
660x1080x000115E0エッジ・ポート2
670x10C0x000115E0エッジ・ポート3
680x1100x000115E0エッジ・ポート4
690x1140x000115E0エッジ・ポート5
700x1180x000115E0エッジ・ポート6
710x11C0x000115E0エッジ・ポート7
720x1200x000115E0ウォッチ・ドッグ
730x1240x000115E0DMA0
740x1280x000115E0DMA1
750x12C0x000115E0DMA2
760x1300x000115E0DMA3
770x1340x000008A4UART0
780x1380x000115E0UART1
790x13C0x000115E0UART2
800x1400x000115E0未使用
810x1440x000115E0I2C
820x1480x000115E0QSPI
830x14C0x000115E0DMA Timer 0
840x1500x000115E0DMA Timer 1
850x1540x000115E0DMA Timer 2
860x1580x000115E0DMA Timer 3
870x15C0x00003378FEC TX frame
880x1600x000033B0FEC TX buffer
890x1640x000033C0FEC TX underrun
900x1680x000032D0FEC Collision retry limit
910x16C0x000031E4FEC RX frame
920x1700x000032E0FEC RX buffer
930x1740x000032F0FEC MII
940x1780x00003300FEC Late Collision
950x17C0x00003310FEC Heartbeat error
960x1800x00003338FEC Graceful stop complete
970x1840x00003348FEC Ethernet bus error
980x1880x00003358FEC Babbling TX error
990x18C0x00003368FEC Babbling RX error
1000x1900x000031D4EPHY
1010x1940x000115E0未使用
1020x1980x000115E0未使用
1030x19C0x000115E0未使用
1040x1A00x000115E0未使用
1050x1A40x000115E0GPT オーバフロー
1060x1A80x000115E0GPT PAC入力
1070x1AC0x000115E0GPT PAC オーバフロー
1080x1B00x000115E0GPT チャネル0
1090x1B40x000115E0GPT チャネル1
1100x1B80x000115E0GPT チャネル2
1110x1BC0x000115E0GPT チャネル3
1120x1C00x000115E0低電圧検出
1130x1C40x000115E0A/Dコンバータ A
1140x1C80x000115E0A/Dコンバータ B
1150x1CC0x000115E0A/Dコンバータ割り込み
1160x1D00x000115E0PWM
1170x1D40x000115E0RNGA
1180x1D80x000115E0未使用
1190x1DC0x00001878PIT0
1200x1E00x000115E0PIT1
1210x1E40x000115E0未使用
1220x1E80x000115E0未使用
1230x1EC0x000115E0Flash buffer empty
1240x1F00x000115E0Flash command complete
1250x1F40x000115E0Flash Protection violation
1260x1F80x000115E0Flash Access error
1270x1FC0x000115E0RTC

こうして見ると、ほとんどが「その他の例外処理ルーチン」である0x000115E0をベクタとして持っています。 使用されているのは、Etherポートの全てとUART0とPIT0です。 これまで調べてきて分かったように、PIT0がオペレーティング・システムの10ミリ秒タイマに使用されており、EthernetとUART0がSilentCとのインターフェースに使用されています。

これらのベクタは、ROMに書き込まれているため、そのままでは使えないと思います。 もし、「その他の例外処理ルーチン」が、割り込み要因によって分岐するような仕掛けを持っていれば、その仕組みを使うことも出来ます。 さて、本当にそんな仕掛けが入っているんだろうか?

参考文献

Interface (インターフェース) 2008年 09月号 [雑誌]

Interface (インターフェース) 2008年 09月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/07/25
  • メディア: 雑誌

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。