Javaネットワークプログラミング入門: java.netでソケット通信・TCP/UDP・ServerSocket/InetAddressをマスター
ネットワークプログラミングとは、複数のデバイス(コンピュータ)上で実行されるプログラムを書くことを指し、これらのデバイスはネットワークを使用して互いに接続されています。
J2SE APIのjava.netパッケージには、低レベル通信の詳細を提供するクラスとインターフェースのコレクションが含まれており、手元の問題解決に集中できるプログラムを書くことができます。
java.netパッケージは2つの一般的なネットワークプロトコルをサポートしています。
- TCP - Transmission Control Protocolの略。2つのアプリケーション間で信頼性の高い通信を可能にする。TCPは通常インターネットプロトコル上で使用され、TCP/IPと呼ばれる。
- UDP - User Datagram Protocolの略。データパケットをアプリケーション間で送信するコネクションレスプロトコル。
この章では以下の2つのテーマについて理解を深めます。
- ソケットプログラミング - ネットワーキングで最も広く使用される概念で、詳細に説明されています。
- URL処理 - 別途扱われます。Java言語でのURL処理についてはこちらを参照してください。
ソケットプログラミング
ソケットはTCPを使用して2台のコンピュータ間の通信メカニズムを提供します。クライアントプログラムは通信の自分の端でソケットを作成し、そのソケットをサーバーに接続しようと試みます。
接続が確立されると、サーバーは通信の自分の端でソケットオブジェクトを作成します。クライアントとサーバーはソケットへの書き込みと読み取りによって通信できます。
java.net.Socketクラスはソケットを表し、java.net.ServerSocketクラスはサーバープログラムがクライアントを待ち受け、接続を確立するメカニズムを提供します。
ソケットを使用して2台のコンピュータ間でTCP接続を確立する際、以下の手順が実行されます。
- サーバーが
ServerSocketオブジェクトをインスタンス化し、通信が発生するポート番号を指定する。 - サーバーが
ServerSocketクラスのaccept()メソッドを呼び出す。このメソッドは、指定されたポートでクライアントがサーバーに接続するまで待機する。 - サーバーが待機状態になると、クライアントが
Socketオブジェクトをインスタンス化し、サーバー名と接続するポート番号を指定する。 Socketクラスのコンストラクタは、指定されたサーバーとポート番号にクライアントを接続しようと試みる。通信が確立されると、クライアントはサーバーと通信可能なSocketオブジェクトを持つ。- サーバー側では、
accept()メソッドがクライアントのソケットに接続されたサーバー側の新しいソケットへの参照を返す。
接続が確立された後、I/Oストリームを使用して通信が行われます。各ソケットにはOutputStreamとInputStreamの両方があります。クライアントのOutputStreamはサーバーのInputStreamに接続され、クライアントのInputStreamはサーバーのOutputStreamに接続されます。
TCPは双方向通信プロトコルであるため、データを両方のストリームで同時に送信できます。ソケットを実装するための完全なメソッドセットを提供する有用なクラスは以下の通りです。
ServerSocketクラスのメソッド
java.net.ServerSocketクラスは、サーバーアプリケーションがポートを取得し、クライアント要求を待ち受けるために使用されます。
ServerSocketクラスには4つのコンストラクタがあります。
| No. | メソッドと説明 |
|---|---|
| 1 | public ServerSocket(int port) throws IOException - 指定ポートにバインドされたサーバーソケットの作成を試みる。ポートが他のアプリケーションによって既にバインドされている場合は例外が発生。 |
| 2 | public ServerSocket(int port, int backlog) throws IOException - 前のコンストラクタと類似。backlogパラメータは待ち行列に格納する着信クライアント数を指定。 |
| 3 | public ServerSocket(int port, int backlog, InetAddress address) throws IOException - 前のコンストラクタと類似。InetAddressパラメータはバインドするローカルIPアドレスを指定。複数のIPアドレスを持つサーバーで、どのIPアドレスでクライアント要求を受け付けるかを指定するために使用。 |
| 4 | public ServerSocket() throws IOException - 未バインドのサーバーソケットを作成。このコンストラクタを使用する場合、サーバーソケットをバインドする準備ができたらbind()メソッドを使用。 |
ServerSocketコンストラクタが例外をスローしない場合、アプリケーションが指定ポートに正常にバインドされ、クライアント要求の準備ができたことを意味します。
ServerSocketクラスの一般的なメソッド:
| No. | メソッドと説明 |
|---|---|
| 1 | public int getLocalPort() - サーバーソケットが待ち受けているポートを返す。コンストラクタでポート番号として0を渡し、サーバーにポートを見つけさせた場合に有用。 |
| 2 | public Socket accept() throws IOException - 着信クライアントを待機。指定ポートでクライアントがサーバーに接続するか、ソケットがタイムアウトするまで(setSoTimeout()でタイムアウト値が設定されている場合)ブロック。それ以外の場合は無期限にブロック。 |
| 3 | public void setSoTimeout(int timeout) - accept()でサーバーソケットがクライアントを待機する時間のタイムアウト値を設定。 |
| 4 | public void bind(SocketAddress host, int backlog) - SocketAddressオブジェクトで指定されたサーバーとポートにソケットをバインド。引数なしコンストラクタでServerSocketをインスタンス化した場合に使用。 |
ServerSocketがaccept()を呼び出すと、クライアントが接続するまでメソッドは返りません。クライアントが接続すると、ServerSocketは未指定のポートで新しいSocketを作成し、この新しいSocketへの参照を返します。クライアントとサーバーの間でTCP接続が確立され、通信を開始できます。
Socketクラスのメソッド
java.net.Socketクラスは、クライアントとサーバーの両方が互いに通信するために使用するソケットを表します。クライアントはSocketオブジェクトをインスタンス化して取得し、サーバーはaccept()メソッドの戻り値からSocketオブジェクトを取得します。
Socketクラスにはクライアントがサーバーに接続するための5つのコンストラクタがあります。
| No. | メソッドと説明 |
|---|---|
| 1 | public Socket(String host, int port) throws UnknownHostException, IOException - 指定されたサーバーの指定ポートに接続を試みる。このコンストラクタが例外をスローしない場合、接続は成功しクライアントはサーバーに接続される。 |
| 2 | public Socket(InetAddress host, int port) throws IOException - 前のコンストラクタと同一だが、ホストがInetAddressオブジェクトで指定される。 |
| 3 | public Socket(String host, int port, InetAddress localAddress, int localPort) throws IOException - 指定ホストとポートに接続し、ローカルホストの指定アドレスとポートにソケットを作成。 |
| 4 | public Socket(InetAddress host, int port, InetAddress localAddress, int localPort) throws IOException - 前のコンストラクタと同一だが、ホストが文字列ではなくInetAddressオブジェクトで指定される。 |
| 5 | public Socket() - 未接続ソケットを作成。このソケットをサーバーに接続するにはconnect()メソッドを使用。 |
Socketコンストラクタが返ると、単にSocketオブジェクトをインスタンス化するだけでなく、実際に指定されたサーバーとポートへの接続を試みます。
Socketクラスの注目すべきメソッドをいくつか示します。クライアントとサーバーの両方がSocketオブジェクトを持つため、これらのメソッドは両方から呼び出せます。
| No. | メソッドと説明 |
|---|---|
| 1 | public void connect(SocketAddress host, int timeout) throws IOException - ソケットを指定ホストに接続。引数なしコンストラクタでSocketをインスタンス化した場合にのみ必要。 |
| 2 | public InetAddress getInetAddress() - このソケットが接続されている相手コンピュータのアドレスを返す。 |
| 3 | public int getPort() - リモートマシンでソケットがバインドされているポートを返す。 |
| 4 | public int getLocalPort() - ローカルマシンでソケットがバインドされているポートを返す。 |
| 5 | public SocketAddress getRemoteSocketAddress() - リモートソケットのアドレスを返す。 |
| 6 | public InputStream getInputStream() throws IOException - ソケットの入力ストリームを返す。入力ストリームはリモートソケットの出力ストリームに接続される。 |
| 7 | public OutputStream getOutputStream() throws IOException - ソケットの出力ストリームを返す。出力ストリームはリモートソケットの入力ストリームに接続される。 |
| 8 | public void close() throws IOException - ソケットを閉じる。このSocketオブジェクトはもはやどのサーバーにも再接続できなくなる。 |
InetAddressクラスのメソッド
このクラスはインターネットプロトコル(IP)アドレスを表します。ソケットプログラミングで必要となる有用なメソッドは以下の通りです。
| No. | メソッドと説明 |
|---|---|
| 1 | static InetAddress getByAddress(byte[] addr) - 生のIPアドレスからInetAddressオブジェクトを返す。 |
| 2 | static InetAddress getByAddress(String host, byte[] addr) - 提供されたホスト名とIPアドレスに基づいてInetAddressを作成。 |
| 3 | static InetAddress getByName(String host) - ホスト名からホストのIPアドレスを決定。 |
| 4 | String getHostAddress() - テキスト表現でIPアドレス文字列を返す。 |
| 5 | String getHostName() - このIPアドレスのホスト名を取得。 |
| 6 | static InetAddress getLocalHost() - ローカルホストを返す。 |
| 7 | String toString() - このIPアドレスをStringに変換。 |
ソケットクライアント例
以下のGreetingClientは、ソケットを使用してサーバーに接続し、挨拶を送信してから応答を待機するクライアントプログラムです。
例
// File Name GreetingClient.java
import java.net.*;
import java.io.*;
public class GreetingClient {
public static void main(String[] args) {
String serverName = args[0];
int port = Integer.parseInt(args[1]);
try {
System.out.println("Connecting to " + serverName + " on port " + port);
Socket client = new Socket(serverName, port);
System.out.println("Just connected to " + client.getRemoteSocketAddress());
OutputStream outToServer = client.getOutputStream();
DataOutputStream out = new DataOutputStream(outToServer);
out.writeUTF("Hello from " + client.getLocalSocketAddress());
InputStream inFromServer = client.getInputStream();
DataInputStream in = new DataInputStream(inFromServer);
System.out.println("Server says " + in.readUTF());
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
ソケットサーバー例
以下のGreetingServerプログラムは、コマンドライン引数で指定されたポート番号でクライアントを待ち受けるサーバーアプリケーションの例です。
例
// File Name GreetingServer.java
import java.net.*;
import java.io.*;
public class GreetingServer extends Thread {
private ServerSocket serverSocket;
public GreetingServer(int port) throws IOException {
serverSocket = new ServerSocket(port);
serverSocket.setSoTimeout(10000);
}
public void run() {
while (true) {
try {
System.out.println("Waiting for client on port " + serverSocket.getLocalPort() + "...");
Socket server = serverSocket.accept();
System.out.println("Just connected to " + server.getRemoteSocketAddress());
DataInputStream in = new DataInputStream(server.getInputStream());
System.out.println(in.readUTF());
DataOutputStream out = new DataOutputStream(server.getOutputStream());
out.writeUTF("Thank you for connecting to " + server.getLocalSocketAddress() + "\nGoodbye!");
server.close();
} catch (SocketTimeoutException s) {
System.out.println("Socket timed out!");
break;
} catch (IOException e) {
e.printStackTrace();
break;
}
}
}
public static void main(String[] args) {
int port = Integer.parseInt(args[0]);
try {
Thread t = new GreetingServer(port);
t.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
クライアントとサーバーをコンパイルし、サーバーを以下のように起動します。
$ java GreetingServer 6066
Waiting for client on port 6066...
クライアントプログラムを以下のように確認します。
出力
$ java GreetingClient localhost 6066
Connecting to localhost on port 6066
Just connected to localhost/127.0.0.1:6066
Server says Thank you for connecting to /127.0.0.1:6066
Goodbye!
Java
- Java演算子をマスター:種類、構文、実践例
- Javaコメント:種類、使い方、ベストプラクティス
- Java拡張forループをマスター:構文、例、ベストプラクティス
- Java文字列をマスター:生成、メソッド、ベストプラクティス
- Javaインターフェース完全ガイド:概念、実装、ベストプラクティス
- Java無名インナークラス完全ガイド:定義、構文、実践例
- Javaのtry-with-resourcesをマスターする:自動リソース管理の仕組みと活用法
- Javaアノテーション完全ガイド:種類、配置場所、実践例
- Javaアサーション完全ガイド:バグ早期発見とコード信頼性の向上
- Java Vectorの理解:使い方、特徴、ArrayListとの比較
- Javaネットワークプログラミング入門: java.netでソケット通信・TCP/UDP・ServerSocket/InetAddressをマスター