■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 2007年09月09日 楽しいJava講座 - 初心者から達人へのパスポート vol.069 セルゲイ・ランダウ バックナンバー: http://www.flsi.co.jp/Java_text/ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ [このメールマガジンは、画面を最大化して見てください。] ======================================================== ◆ 01.ネットワーク系のプログラミング ======================================================== UDPによるソケット通信の手順を簡単に説明しましょう。 まず、クライアントは通信の窓口を開くためにソケットのオブジェ クト(インスタンス)を生成しますが、このときTCPとは異なり、 相手(サーバー)のIPアドレスとポート番号を指定する必要はありま せん。 UDPでは、サーバーへの接続は行わず、相手につながっているかどうか を確認することなく、いきなりデータを送りつけるので、データの 送信時に指定すれば済むからです。 このソケットのインスタンス生成は、例えば -------------------------------------------------------- DatagramSocket socket = null; socket = new DatagramSocket(); -------------------------------------------------------- という形式で、行います。 上記を見るとわかるように、UDPの場合のソケットのクラス名は DatagramSocketです。 (DatagramSocketはjava.netパッケージにはいっています。) なお、なんらかの理由でDatagramSocketのインスタンス生成ができ なかった場合にはSocketExceptionが発生します。 UDPによるソケット通信では、データはデータグラム・パケット (Datagram Packet)と呼ばれる形式で送信されます。 パケット(Packet)の元々の意味は「小包」ですが、ネットワーク における用語としては、一つの送信作業で送られるデータの単位 (一まとめのデータ)を意味します。いくつかの品物を小包に一ま とめにして送るイメージから、いくつかのデータを一まとめにして (それをパケットと呼び)送信するわけです。 データグラム(Datagram)というのは、(重さの)単位を表すグラム (gram)とデータを組み合わせて作られた造語で、データの単位を 意味します。つまり、パケットと同じ意味です。 (なお、gramにはまたギリシャ語からの借用で(データが)「書かれた もの」という意味もある。) ただし、パケットが汎用的に使われる言葉なのに対し、データグラム はUDPに限定して使われる言葉です。 データグラム・パケットには、データのほかに宛先も書かれます。 つまり送信先のIPアドレス、ポート番号も書かれます。 データグラム・パケットは以下のようにして作成します。 -------------------------------------------------------- DatagramPacket packet = null; packet = new DatagramPacket(データ, データの長さ, IPアドレス, ポート番号); -------------------------------------------------------- つまり、送信するデータ, データの長さ, 送信先のIPアドレス, 送信先 のポート番号を指定してDatagramPacketクラスのインスタンスを生成 します。(DatagramPacketはjava.netパッケージにはいっています。) この引数の型は以下の通りです。 -------------------------------------------------------- データ : byte[] データの長さ : int IPアドレス : InetAddress ポート番号 : int -------------------------------------------------------- ここで、InetAddressというのは、IPアドレスを表現するクラスで、 java.netパッケージにはいっています。 ┌補足─────────────────────────┐ IPアドレスの形式には、現在主として使われているIPv4(IPバージョン4) の形式と、今後普及してくるIPv6(IPバージョン6)の形式の2種類があり ます。 (ちなみにIPv5というものもIPv6の前に一時提案されましたが、現在は 消滅しています。) IPv4では、IPアドレスは4バイト(32ビット)で表現され、1バイトずつ 10進数で書き、各バイトの間にピリオド(.)を入れて表記する習慣になっ ています。 たとえば、 -------------------------------------------------------- 123.45.67.212 -------------------------------------------------------- というように表記します。 なお、IPアドレスには、いくつかの特殊な目的で使用される番号があり ます。 たとえば、 192.168.0.0から192.168.255.255までのIPアドレスは、プライベイト (個人的)なネットワーク(private network)用の番号であり、家庭や 会社のLAN環境などの私的なネットワーク内でのみ個人が自由に 使える番号になっています。 詳しくは、 http://www.ietf.org/rfc/rfc3330.txt などを参照してください。 一方、IPv6では、IPアドレスは128ビットで表現され、16ビット(2バイト) ずつ16進数で書き、各16ビットの間にコロン(:)を入れて表記する習慣に なっています。 たとえば、 -------------------------------------------------------- ABCD:EF12:3456:7890:12AB:34CD:56EF:AB78 -------------------------------------------------------- というように表記します。 IPv4形式のIPアドレスではアドレスが不足しつつあるために、IPv6形式の IPアドレスが作られたのであり、今後はIPv6形式が段々と普及してきて、 最終的には全てのIPアドレスがIPv6形式に代わることになります。 しかし、当分の間は、主にIPv4形式のIPアドレスにお世話になることに なるでしょう。 というわけで、当メールマガジンでも特に断らない限り、IPv4形式のIPア ドレスを使用します。 └───────────────────────────┘ InetAddressにはInet4AddressとInet6Addressという2つのサブクラスがあり、 それぞれIPv4形式のIPアドレスとIPv6形式のIPアドレスを表現しています。 なお、IPアドレスは数字の羅列で覚えにくいので、通常はIPアドレスの代わり にホスト名(IPアドレスに対応付けられた(ホストの)名前)を使用すること が多いです。 ホスト名は、簡単なLANの環境であればhostsというファイル(たとえば Windows XPであれば、C:\WINDOWS\system32\drivers\etcにhostsファイルが 入っています。hostsファイルは普通のテキスト・ファイルです)に登録され ることによって、あるいは本格的なネットワークやインターネットであれば DNS(Domain Name System)という、ドメイン名(Domain Name)を管理する コンピューターに登録されていることによって、利用することができます。 (ドメイン名はホスト名と同じものと思って差し支えありませんが、厳密に はドメイン名はホスト名とは若干意味が異なり、IPアドレスに対応していな いことがあります。) そして、ホスト名からIPアドレスを知りたいときには、 InetAddress ipAddress = InetAddress.getByName("ホスト名"); というふうにInetAddressのgetByName()メソッド(staticメソッド)を使う ことができます。(なお、このとき、もし該当するホストが見つからない 場合にはUnknownHostExceptionが発生します。) たとえば、localhostのIPアドレスを知りたいときは InetAddress ipAddress = InetAddress.getByName("localhost"); とします。 あるいは、sun.comの IPアドレスを知りたいときは InetAddress ipAddress = InetAddress.getByName("sun.com"); とします。 なお、InetAddressのオブジェクトのままでは数値のIPアドレスはわかり ませんので、toString()メソッドを使って、文字列を受け取るか、あるい はgetAddress()メソッドを使って、数値(byteの配列)を受け取ります。 たとえば、 byte[] address = ipAddress.getAddress(); としてから、 System.out.println("IP address = " + address[0] + '.' + address[1] + '.' + address[2] + '.' + address[3]); とすれば数値のIPアドレスをコンソールに表示させられます。 ちょっとわき道にそれましたが、たとえば、5, 4, 3, 2, 1というデータ (byte型の数値の配列)を同じパソコン内の49152というポート番号の プログラムに送り込むには、 -------------------------------------------------------- byte[] outData = {5, 4, 3, 2, 1}; int outLength = outData.length; DatagramPacket packet = null; packet = new DatagramPacket(outData, outLength, InetAddress.getByName("localhost"), 49152); -------------------------------------------------------- というふうにしてデータグラム・パケットを作ればいいことがわかりますね。 そして、このパケットを送信するにはDatagramSocketのsend()メソッドを 使って、 -------------------------------------------------------- socket.send(packet); -------------------------------------------------------- のようにします。 そして、送信が終わったら、ソケットをクローズします。 -------------------------------------------------------- socket.close(); -------------------------------------------------------- では、クライアントのソース・コードを確認してみてください。 [UDPを使ったクライアント] -------------------------------------------------------- import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; public class UdpSocketClient { public static void main(String[] args) { DatagramSocket socket = null; byte[] outData = {5, 4, 3, 2, 1}; int outLength = outData.length; DatagramPacket packet = null; try { socket = new DatagramSocket(); } catch (SocketException e) { e.printStackTrace(); } try { packet = new DatagramPacket(outData, outLength, InetAddress.getByName("localhost"), 49152); System.out.println("Data 54321 sent."); } catch (UnknownHostException e1) { e1.printStackTrace(); } try { socket.send(packet); } catch (IOException e) { e.printStackTrace(); } socket.close(); } } -------------------------------------------------------- 問題なく理解できますね。 続いてサーバーのほうを説明しましょう。 サーバーでは、ソケットのインスタンス生成時にポート番号を指定して おきます。 例えば -------------------------------------------------------- DatagramSocket socket = null; socket = new DatagramSocket(49152); -------------------------------------------------------- というふうにします。 続いてデータグラム・パケットのインスタンスを生成しますが、受信側 なのでIPアドレス、ポート番号は指定しません。 代わりに次のように行います。 -------------------------------------------------------- DatagramPacket packet = null; packet = new DatagramPacket(データ, データの長さ); -------------------------------------------------------- たとえば、 -------------------------------------------------------- byte[] inData = new byte[5]; int inLength = inData.length; DatagramPacket packet = null; packet = new DatagramPacket(inData, inLength); -------------------------------------------------------- このとき、データを入れる配列の要素数(データの長さ)は送信側に合わ せるようにしてください。もし、データの長さが不足していると、データ が入りきらなかった分は単純に消失するだけであり、エラーも何も出ませ ん。UDPは信頼性が保証されないプロトコルなのです。 次にデータの受信ですが、 -------------------------------------------------------- socket.receive(packet); -------------------------------------------------------- というふうにDatagramSocketのreceive()メソッドを使います。 サーバーは通常、この処理をループで繰り返すことになります。 サーバーのプログラムを終了するときには、 -------------------------------------------------------- socket.close(); -------------------------------------------------------- というふうにソケットをクローズしておきます。 では、サーバーのソース・コードを確認してみてください。 [UDPを使ったサーバー] -------------------------------------------------------- import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; public class UdpSocketServer { public static void main(String[] args) { DatagramSocket socket = null; byte[] inData = new byte[5]; int inLength = inData.length; DatagramPacket packet = null; try { socket = new DatagramSocket(49152); } catch (SocketException e) { e.printStackTrace(); } packet = new DatagramPacket(inData, inLength); for(int n = 0; n < 5; n++) { try { socket.receive(packet); } catch (IOException e) { e.printStackTrace(); } for (int i = 0; i < inLength; i++) { System.out.print(inData[i]); } System.out.println(); } socket.close(); } } -------------------------------------------------------- これも容易に理解できますね。 では、次回はいよいよTomcatを使うべくツール類を整えていきます。 何か、わからないところがありましたら、下記のWebページまで質問を お寄せください。 (続く) ======================================================== ◆ 02.Java(文法等)解説 [JavaBeans (4)] ======================================================== [JavaBeans (4) イベント<1>] ActionEventなどの既存のイベントについては既にお話しましたが、 自分で独自のイベントを作ることもできます。 独自のイベントは以下の作業によって定義されます。 (仮にMyOwnEventという名前のイベントにします。) (1) イベント・オブジェクトの定義 EventObjectクラスを継承したMyOwnEventクラスを定義します。 (2) イベント・リスナーのインターフェースの定義 EventListenerインターフェースを拡張してMyOwnEventListenerと いうインターフェースを作り、イベント通知時に呼び出されるメ ソッド(リスナー・メソッド)を定義します。 (続く) 以上、今回は ┌───────────────────────────┐ ・UDPによるソケット通信のプログラミング ・InetAddressクラスの使いかた └───────────────────────────┘ を学習しました。 では、また来週。 ================================================ ◆ 03.演習問題 ================================================ 1. 上記のInetAddressの使い方を理解するために次のようなプログラム を作って実行してみてください。 -------------------------------------------------------- import java.net.InetAddress; import java.net.UnknownHostException; public class InetAddressTest { public static void main(String[] args) { InetAddress ipAddress; byte[] address; try { ipAddress = InetAddress.getByName("localhost"); System.out.println(ipAddress.toString()); address = ipAddress.getAddress(); System.out.println("IP address = " + address[0] + '.' + address[1] + '.' + address[2] + '.' + address[3]); } catch (UnknownHostException e) { e.printStackTrace(); } try { ipAddress = InetAddress.getByName("sun.com"); System.out.println(ipAddress.toString()); address = ipAddress.getAddress(); System.out.println("IP address = " + address[0] + '.' + address[1] + '.' + address[2] + '.' + address[3]); } catch (UnknownHostException e) { e.printStackTrace(); } } } -------------------------------------------------------- 2. UdpSocketServerのソース・コードの中の -------------------------------------------------------- byte[] inData = new byte[5]; -------------------------------------------------------- の部分を -------------------------------------------------------- byte[] inData = new byte[2]; -------------------------------------------------------- に書き換え(つまり送信側より配列の要素数を少なくして)、ソケット 通信のテストをしてみてください。 エラー(Exception)は出ないけれど、データが部分的に消失すること を確認してください。 ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ★ホームページ: http://www.flsi.co.jp/Java_text/ ★このメールマガジンは 「まぐまぐ(http://www.mag2.com)」 を利用して発行しています。 ★バックナンバーは http://www.flsi.co.jp/Java_text/ にあります。 ★このメールマガジンの登録/解除は下記Webページでできます。 http://www.mag2.com/m/0000193915.html ★このメールマガジンへの質問は下記Webページにて受け付けて います。わからない所がありましたら、どしどしと質問をお寄 せください。 http://www.flsi.co.jp/Java_text/ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ Copyright (C) 2007 Future Lifestyle Inc. 不許無断複製 |