サブネットアドレス
あらかじめ割り当てられたホスト部から、任意のビット数をサブネット部として割り当てる方式をサアドブネットレスと呼びます。例えば、ネットワーク部が218.234(2進数表記:11011010 11101010)のクラスBのIPアドレスを取得したとします。クラスBですから65534台ものホストを接続できます。しかし、よほど大規模なネットワークでない限りこのような膨大な数のホストは要りません。そこで、サブネット部として7ビット割り当てるとします。そうすれば、ホスト部は9ビットとなり、2つの特別なアドレスを引くと510台のホストが接続できる、126のサブネットが使用できることになります。なお、サブネット部も全て0と1のアドレスは使用できません。こうすることにより、複数の拠点を持つネットワークを構築できることになります。こうすることの利点は、支店ごとにサブネット部を変えるなどの柔軟なネットワークの構築ができることです。
サブネットアドレスは、「218.234.11.100/23」のようにスラッシュ記号の横に、ネットワーク部のビット数+サブネット部のビット数の数値をつけて表現します。また、ネットワーク部+サブネット部を全て1として、「255.255.254.0」と表現するネットマスクという概念もあります。
このアドレスの形式は一見複雑ですが、クラスアドレス形式とほぼ同じです。SubNetAddressTestテストプロジェクトを用意しましたので実行してみて下さい。先ほど実行したClassAddressTestプロジェクトとほぼ同じことが分かると思います。このプロジェクトのMainメソッドを見て下さい。サブネットを考慮する以外の違いがないことがコードで確認できます。
//クラスBのネットワーク1 byte bBit = 26; string aStr = "168.44.38.67/" + bBit.ToString ( ); //「/」でサブネットを指定している点に注意 MacAddress macA = new MacAddress ( 100, 100 ); SubNetAddress aAddress = new SubNetAddress ( AddressClass.B, bBit ); aAddress.Address = SubNetAddress.Parse ( aStr ); Router aRouter = new Router ( macA, aAddress, AddressFormat.ClassAddress, new Lan ( ), net ); aRouter.LanName = "クラスBのネットワーク其の一"; //----------途中省略---------- //クラスBのネットワーク其の一からクラスCのネットワークへデータ送信 SubNetAddress destination = new SubNetAddress ( AddressClass.C, cBit, SubNetAddress.Parse ( cStr ) ); MacFrame data = new MacFrame ( ); data.TypeOrLength = ( ushort ) EtherType.IP; IPv4 userData = new IPv4 ( ); userData.DestinationAddress = destination; data.UsertData = userData; aRouter.Send ( destination, data );
'クラスBのネットワーク1 Dim bBit As Byte = 26 Dim aStr As String = "168.44.38.67/" + bBit.ToString() '「/」でサブネットを指定している点に注意 Dim macA As MacAddress = New MacAddress(100, 100) Dim aAddress As SubNetAddress = New SubNetAddress(AddressClass.B, bBit) aAddress.Address = SubNetAddress.Parse(aStr) Dim aRouter As Router = New Router(macA, aAddress, AddressFormat.ClassAddress, New Lan(), net) aRouter.LanName = "クラスBのネットワーク其の一" '----------途中省略---------- 'クラスBのネットワーク其の一からクラスCのネットワークへデータ送信 Dim destination As SubNetAddress = New SubNetAddress(AddressClass.C, cBit, SubNetAddress.Parse(cStrs)) Dim data As MacFrame = New MacFrame() Data.TypeOrLength = CUShort(EtherType.IP) Dim userData As IPv4 = New IPv4() userData.DestinationAddress = destination Data.UsertData = userData aRouter.Send(destination, data)
その他にもCIDR(Classless InterDomain Routing)と呼ばれるアドレスもあります。CIDRは先の項で述べたIPv4のアドレス枯渇問題を解決するための時間を稼ぐために考え出された技術です。このアドレスは、ネットワークアドレスとネットマスクを使って、ネットワークとホストを表す技術です。このアドレスについては今回詳しく説明しませんが、サブネットアドレスの考えが分かれば十分に分かるものです。ですから、この記事の内容をマスターしてから、時間がある時に調べてみてください。ちなみに、次世代規格であるIPv6では基本的にクラスレスです。
MACアドレスの解決とARP
端末同士が通信するには必ずMACアドレスが必要となります。ですから指定したIPアドレスがどのMACアドレスに対応しているのかを知らねば通信が実現できません。そこで、IPアドレスから対応するMACアドレスなどのハードウェア・アドレスへの動的なマッピングを提供するARP(Addres Resolution Protocol:アドレス解決プロトコル)が考え出されました。ARPは正確に言うと、ネットワークアクセス層のプロトコルなのですが、IPアドレスの解説が必須になるので今回紹介しています。
ARPは簡単なプロトコルで、自分が属するネットワーク上の全てのホストに、ARP要求と呼ばれるMACフレームを1つ送信します。この一斉に全てのホストにフレームを送信する方式をブロードキャストと呼びます。ARP要求を受け取ったホストは、自分のIPアドレスと一致するか調べて、自分のものならばARP応答と呼ばれるMACフレームを送信元に送ります。なお、MACアドレスを知りたい状況で毎回ARP要求を送るのは非効率的なので、一定時間ARP応答の結果をキャッシュしておき、キャッシュ内に対象となるホストのMACアドレスがある場合はそのアドレスを使用します。コードでこの動きを表現すると次のようになります。
/// <summary> /// 指定したIPアドレスを持つホストのMACアドレスを探索します。 /// </summary> /// <param name="target">対象となるホストのIPアドレス</param> /// <returns> /// 指定したIPアドレスに対応するMACアドレス。 /// 見つからない場合はNullを返します。 /// </returns> public MacAddress Seach (IPv4Address target) { //キャッシュを検索 MacAddress result = null; bool flag = this.cash.TryGetValue ( target, out result ); //見つからないのでARP要求フレームを送出 if ( flag == false ) { ArpFream fream = new ArpFream ( ); fream.SourceAddress = this.sendMacAddress; fream.DestinationAddress = MacAddress.GetBroadcastAddress ( ); //全てのビットを1(ブロードキャスト) fream.SenderIPAddress = this.sendIpAddress; fream.TypeOrLength = ( ushort ) EtherType.ARP; fream.PurposeIPAddress = target; fream.OperationCode = ArpOpe.ArpRequest; this.lan.BroadcastData ( fream ); this.cash.TryGetValue ( target, out result ); } //結果を返す return result; } /// <summary> /// PCから送られてきたデータを選別し、IPアドレスとMACアドレスの対応関係を記録します。 /// </summary> void LAN_SendData ( object sender, DataFlowEventArgs e ) { //ARPに関するフレーム以外は無視する ArpFream fream = e.Data as ArpFream; if ( fream == null ) return; //ARP応答以外のフレームは無視する if ( fream.OperationCode != ArpOpe.ArpReply ) return; //要求するホストに対する応答フレームから、アドレスの対応関係を取り出して記録。 if ( this.sendIpAddress == fream.PurposeIPAddress && this.sendMacAddress == fream.DestinationAddress ) { if(this.cash.ContainsKey(this.sendIpAddress) == false) this.cash.Add ( fream.SenderIPAddress, fream.SourceAddress ); } }
''' <summary> ''' 指定したIPアドレスを持つホストのMACアドレスを探索します。 ''' </summary> ''' <param name="target">対象となるホストのIPアドレス</param> ''' <returns> ''' 指定したIPアドレスに対応するMACアドレス。 ''' 見つからない場合はNothingを返します。 ''' </returns> Public Function Seach(ByVal target As IPv4Address) As MacAddress 'キャッシュを検索 Dim result As MacAddress = Nothing Dim flag As Boolean = Me.cash.TryGetValue(target, result) '見つからないのでARP要求フレームを送出 If flag = False Then Dim fream As ArpFream = New ArpFream() fream.SourceAddress = Me.sendMacAddress fream.DestinationAddress = MacAddress.GetBroadcastAddress() '全てのビットを1(ブロードキャスト) fream.SenderIPAddress = Me.sendIpAddress fream.TypeOrLength = CUShort(EtherType.arp) fream.PurposeIPAddress = target fream.OperationCode = ArpOpe.ArpRequest Me.lan.BroadcastData(fream) Me.cash.TryGetValue(target, result) End If '結果を返す Return result End Function ''' <summary> ''' PCから送られてきたデータを選別し、IPアドレスとMACアドレスの対応関係を記録します。 ''' </summary> Private Sub LAN_SendData(ByVal sender As Object, ByVal e As DataFlowEventArgs) 'ARPに関するフレーム以外は無視する If TypeOf e.Data Is ArpFream = False Then Return End If Dim fream As ArpFream = CType(e.Data, ArpFream) 'ARP応答以外のフレームは無視する If fream.OperationCode <> ArpOpe.ArpReply Then Return End If '要求するホストに対する応答フレームから、アドレスの対応関係を取り出して記録。 If Me.sendIpAddress = fream.PurposeIPAddress AndAlso _ Me.sendMacAddress = fream.DestinationAddress Then If Me.cash.ContainsKey(Me.sendIpAddress) = False Then Me.cash.Add(fream.SenderIPAddress, fream.SourceAddress) End If End If End Sub
この動作を確認するためにArpTestサンプルプロジェクトを実行して下さい。一度目の通信時にはIPアドレスとMACアドレスの対応が分からずARP要求フレームが送出され、二度目の通信時にはキャッシュが使われてMACアドレスを即答していることが確認できます。
これで異なるネットワーク間に属するホスト(端末)同士が通信をする仕組みを解説しました。次項では実際にサンプルプロジェクトを動かしてその動作を解説します。