今回は、いよいよネットワーク通信機能を実装していく。ネットワーク通信のような複雑なプログラムを実装すると、“マルチタスク構成にすることの有用性”がこれまで以上に実感できるはずだ。
本連載では、学習用・ホビー用の組み込みOS「KOZOS」を使って、マイコンボード上でいろいろと実験をしつつ、フルスクラッチで組み込みOSを自作していく過程を体験していきます。最終的に、ソフトウェア完全自作のWebサーバを動かすことにチャレンジします!
前回「コマンド応答をマルチタスクで実装してみよう」では、コマンド応答プログラムをマルチタスク構造で実装し、“サービスをマルチタスクで構成すること”のメリットを説明しました。
今回は、いよいよ“ネットワーク通信機能を実装”していきます。ネットワーク通信のような複雑なプログラムを実装すると、マルチタスク構成にすることの有用性がこれまで以上に実感できるはずです。
本連載では、秋月電子通商の「H8/3069Fネット対応マイコンLANボード(完成品)」(図1)を利用します。マイコンボードの詳細については連載第1回を参照してください。ちなみにこのボードは、3750円(税込)と非常に安価で入手性もよく、個人のホビー用途にオススメです。
本連載で紹介するソースコードは、これまでKOZOSのWebサイトからダウンロードして利用してきました。しかし、KOZOSのWebサイトで紹介しているのは、組み込み向けマルチタスクカーネルを実装するまでの内容であるため、今回からはそれに“プラスα”する形で、ネットワーク機能を実装していきます。
今回使用するソースコードは、ここからダウンロードしてください。
関連リンク: | |
---|---|
⇒ | (H8移植編その2 第5回)IP通信をごっそり書き直した |
また、開発環境の構築方法は連載第1回で説明してありますので、興味のある方はぜひソースコードをビルドし、実機での動作を試してみてください(幾つか対応は必要となりますが、シミュレータ上でも動作させることが可能です)。
なお、本連載で利用する組み込みOS、KOZOSのカーネル構造については、筆者の書籍「12ステップで作る組込みOS自作入門」に詳しい説明がありますので、そちらも参考にしてみてください。
さて、今回実装するのは“ICMP Echoによる通信”です。いわゆる「ping」と呼ばれているものです。
pingは、特定のホストとの「疎通確認」に利用されます。WindowsのコマンドプロンプトやUbuntuなどのGNU/Linuxディストリビューションで、
ping <通信相手>
のようにコマンド実行することで、「ICMP Echo」というパケットを通信相手に送信できます。これに対して、相手が「ICMP Echo Reply」を返すことで、相手までの通信路が確立されていることが確認できます。
リスト1は、FreeBSDのホストから、別のホスト(192.168.1.1)に対してpingを発行した例です。192.168.1.1からの応答として、ICMP Echo Replyが返ってきており、疎通確認できていることが分かります。
hiroaki@hotroom:~>% ping 192.168.1.1 PING 192.168.1.1 (192.168.1.1): 56 data bytes 64 bytes from 192.168.1.1: icmp_seq=0 ttl=64 time=2.547 ms 64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=7.407 ms 64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=1.669 ms 64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=3.329 ms 64 bytes from 192.168.1.1: icmp_seq=4 ttl=64 time=3.277 ms ^C --- 192.168.1.1 ping statistics --- 5 packets transmitted, 5 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 1.669/3.646/7.407/1.975 ms hiroaki@hotroom:~>%
pingの通信機能を実装する際、幾つかのネットワーク機能が必要となってきます。ここでは、代表的な以下の3つのプロトコルを実装することにします。
もっとも、実際のネットワーク通信では、IPではなく「IPv6」が利用されたり、Ethernetでなく「PPP」が利用されたりするなど、階層ごとに別のプロトコルも存在します。しかし、本稿では内容を分かりやすくするため、Ethernet、IP、ICMPのみに限定して解説していきます。
Ethernetは、複数の隣接ノードとの双方向通信を行うためのプロトコルです。しかし、Ethernetはあくまで“隣接ノードと通信するためのもの”です。Ethernetで利用される「MACアドレス」は、LANコントローラーに固定で与えられているハードウェアアドレスであり、ハードウェア制御には向いているのですが、アドレスを見て転送先を切り替える「ルーティング」のような制御には向いていません。例えば、仮にMACアドレスベースで転送先制御をしようとすると、全ノードのMACアドレスとその転送先を記憶しておく必要があり、ネットワークのスケーラビリティに対応できないためです。
これに対して、IPがあります。IPは「IPアドレス」によってホストを指定することで、遠距離のホストとの通信をするためのプロトコルです。IPアドレスは、32ビットCPUでのソフトウェア制御に適した設計がなされています。また、後付けで自由に設定できるソフトウェアアドレスで、ホストに自由に割り当てることが可能です。このため、規則性を持たせることが可能で、転送先制御がアドレスのパターンによって行えるため、全アドレスを記憶する必要はなく、ルーティング処理に向いています。ネットワークのスケーラビリティに対応できるため、IPを利用すれば地球の裏側にあるホストとも通信ができます。
ICMPは、エラー通知などを行うための通信路制御用のプロトコルですが、本稿ではICMP Echoによるネットワークの疎通確認のために利用することにします。
これらのプロトコルは“階層構造”になっています。例えば、ICMPの通信のためにはIPによる相手ホストの指定が必要ですし、IP通信のためには隣接ノードとの通信のためのEthernetが必要になります。つまり、ICMPのデータとヘッダにIPヘッダが付加されてIPパケットとなり、さらに、それにEthernetヘッダが付加されてEthernetフレームとなります。これを図示すると図2のようになります。「Ethernetの隣接ノード間通信を利用してIP通信が行われ、IP通信によってICMPのデータが転送される」ということになります。
ICMP EchoとICMP Echo Replyを実装することは、それほど難しいことではありません。パケットの送受信ができればいいだけですから、LANコントローラーのデバイスドライバさえ作成してしまえば、後はEthernetフレーム、IPパケット、ICMPパケットの構築と解釈を行うプログラムを作成すればいいだけです。
しかし、実際はそれだけでは通信できません。Ethernet上でのIP通信には、「ARPによるMACアドレス解決」が必要になります。
Ethernetは、ノードが“1対1”に接続されたPoint to Pointの構成ではなく、1つのバス上に複数のノードが接続されている「マルチリンクネットワーク」です。このため、各ノードは個々の識別のためにMACアドレスを持っており、通信時には相手のMACアドレスを指定してフレームを送信する必要があります。
具体的にいうと、LANコントローラーはバス上に流れているフレームを見て、自身のMACアドレス宛てのもののみ受信して、CPUに対して割り込みを発行します。この処理はハードウェアで行われるため、MACアドレスが異なるフレーム(他ノード宛のフレーム)はハードウェア的に無視されることになります。
つまり、通信のためには相手のMACアドレスを知る必要があるわけですが、バス上の全てのノードのMACアドレスを手作業で登録するのは大変面倒です。このため、実際にはIPアドレスからMACアドレスを知るための「ARP」というプロトコルを利用して、MACアドレスを取得します。よって、通信機能を実現するためには、“ARPの送受信機能”も実装する必要があるのです。
実際の通信は、以下の手順で行われます。
このように、まずはARPでMACアドレスを問い合わせ、その後に本来のパケットを送信するという2段階構成になります。つまり、パケットの送信時には、いきなりそのパケットを送信できるわけではありません。前もってARPによるMACアドレス解決を行う必要があるわけです。
これは、送信処理のどこかでパケットを一時的に“保留”しておく機構が必要ということになります。そして、ARPの応答を受けてMACアドレス解決がされた時点で、送信が保留されているパケットを再送信する(フラッシュする)ような処理が必要になるわけです。
Copyright © ITmedia, Inc. All Rights Reserved.